1.string结构体底层
由两部分组成:指向底层[ ]byte数组的指针;长度。(类似切片结构体)
2.相同的string常量不会重复存储
//由s1、s2的指针指向一块相同的只读内存,这段内存以utf-8编码存放hello数组
s1 := "hello"
s2 := "hello"
3.string常量会在编译期分配到只读段,对应数据地址不可写入,故string不支持修改。
要修改必须转[]byte,string和[]byte转换,会将这段只读内存的数据复制到堆/栈上。
//wrong
s := "hello"
s[0] = 'A'
//right
s := "hello"
a := []byte(s)
a[0] = 'H'
s = string(a) //s="Hello"
package main
import "fmt"
/go的本质是值拷贝,但string底层是指针
/故 函数参数变量s也是一段新地址,但是底层指针指向的地址与main中s相同,为存储数据的空间
func change(s string) string {
fmt.Printf("%#v\n", &s)
a := []byte(s)
a[0] = 's'
return string(a)
}
func main() {
s := "abcd"
fmt.Printf("%#v\n", &s)
s2 := change(s)
fmt.Printf("%#v\n", &s2)
}
整体反转可以整体转为[]byte,不能把string类型作为参数直接传进来
Q:那怎么在原字符串上进行 部分反转?
输入: “abcd”
输出:“acbd”
部分反转错误解法,change返回的是“cb”,而不是“acbd”
func main() {
s := "abcd"
s = change(s[1:3])
fmt.Println(s)
}
func change(s string) string {
a := []byte(s)
i := 0
j := len(a)-1
for i < j {
a[i],a[j] = a[j],a[i]
}
return string(a)
}
反转正确解法
1.
func main() {
s := "abcd"
a := []byte(s)
change(a,1,2)
fmt.Println(a)
}
func change(a []byte,i int, j int) {
for i < j {
a[i],a[j] = a[j],a[i]
i++
j--
}
}
2.
func main() {
s := "abc"
a := []byte(s)
change(a)
fmt.Println(string(a))
}
func change(a string) {
i := 0
j := len(a)-1
for i < j {
a[i],a[j] = a[j],a[i]
i++
j--
}
}
leetcode:1143
谨记,string类型的变量,其s[i]是byte = uint8类型,只能往同类型[]byte中添加
s := "abc"
fmt.Printf("%T s[0] = \n",s[0],s[0])
//输出结果如下:
uint8 s[0]=90
大坑:对string for range后,类型是int32,即rune !!
s := "("
for _,v := range s {
fmt.Printf("%T",v)
}
//输出结果如下:
int32
leetcode:150
s := []string{"2", "1", "+", "3", "*"}
fmt.Printf("%T\n",s[0])
//输出结果如下:
s[0]的类型是string
s := "abc"
fmt.Printf("%T\n",s[1]-'a')
fmt.Println(s[1]-'a ')
//输出结果如下:
uint8 // = byte
1
4.string与int的转换
注意:strconv.Atoi返回值是两个,strconv.Itoa返回值是一个
strconv.Atoi(string) (int,err)
strconv.Itoa(int) string
leetcode:412
//1.right string转成int
str := "123"
int, err := strconv.Atoi(str) //to int 参数必须是string
str := "123"
int, err := strconv.Atoi(str[0]) ////wrong 此处参数是byte
int, err := strconv.Atoi(string(str[0])) //right
//string转成int
Question : Int(s[0]-'0') //得到数字1
//2.int转成string
i := 1
str := strconv.Itoa(i)
//3.ASCII转成string
s := "hello"
fmt.Println(s[0]) //得到ASCII,是byte类型,即uint8。byte等价于uint8,只是用byte来说明这是一个字符的ASCII数字
fmt.Println(string(s[0])) //得到 "h"
大坑:单引号在 Golang 表示一个字符,使用一个特殊类型 rune 表示字符型。rune 为 int32 的别名,它完全等价于 int32
wrong! a的类型是int32,s[0]的类型是uint8 byte,无法赋值给a
a := 'c'
s := "bcd"
a = s[0]
lc 443
int与byte直接转好像是错的
a := 15
b := byte(a) //=unit
负数的string转int64
s := "-11"
n,err := strconv.ParseInt(s, 0, 64) //s可以转时,err=nil
fmt.Println("n = ",n) // n = -11
fmt.Println(err) // err = nil
fmt.Printf("%T\n",n) // int64
5.string中含中文
utf-8编码时,每个中文占3个字节,英文占1个字节
s := "abc中国"
len(s) //=9,len求的是底层所占字节数
len([]rune(s)) //=5,[]rune会将utf-8编码转为unicode编码
6.对string进行for range循环,返回的value是rune类型
s := "我是中国人c"
for index, runeValue := range s {
fmt.Printf("%#U 起始于字位置%d\n", runeValue, index)
}
// 输出结果如下:
我 起始于字位置0
是 起始于字位置3
中 起始于字位置6
国 起始于字位置9
人 起始于字位置12
c 起始于字位置13
7.排序 https://learnku.com/articles/38269
1.针对切片排序
s := []string{"abc","def","acd"}
sort.Ints(a)
sort.Strings(s)
2.针对字符串排序 leetcode:49
str := "cab" //想得到“abc”
1)leetcode:49、56
mybyte := []byte(str)
sort.Slice(mybyte, func(i, j int) bool { return bytes[i] < bytes[j]})
2)
type mybyte []byte //类型定义
func (b mybytes) Len() int {
return len(b)
}
func (b mybyte) Less(i,j int) bool {
return b[i] < b[j]
}
func (b mybyte) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
k := mybyte(str)
sort.Sort(k)
79.拼接得到最大值
输入:nums = [3,30,34,5,9]
输出:“9534330”
注意:
1)strconv.Itoa,不是strings.
2) sort.Slice整体用法,括号位置+记得return
func largestNumber(nums []int) string {
ans := []string{}
for _,num := range nums {
ans = append(ans,strconv.Itoa(num))
}
sort.Slice(ans,func (i,j int) bool {
return ans[i]+ans[j] > ans[j]+ans[i]
})
if ans[0] == "0" {
return "0"
}
res := ""
for _,v := range ans {
res += v
}
return res
}
package sort
type Interface interface {
Len() int // 获取元素数量
Less(i, j int) bool // i,j是序列元素的指数。
Swap(i, j int) // 交换元素
}
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
}
/* 定义结构体 */
type struct_name struct {
...
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
...
}
func (struct_name_variable struct_name) method_name2() [return_type] {
...
}
Go语言的 sort.Sort 函数不会对具体的序列和它的元素做任何假设。相反,它使用了一个接口类型 sort.Interface 来指定通用的排序算法和可能被排序到的序列类型之间的约定。为了对序列进行排序,我们需要定义一个实现了这三个方法的类型,然后对这个类型的一个实例应用 sort.Sort 函数
为了让 sort 包能识别 mybyte,能够对 mybyte 进行排序,就必须让mybyte实现 sort.Interface 接口,一个类型实现接口=该类型实现sort包 interface 中的所有方法
7.常用的string函数 leetcode:151
返回 str 空格分隔的所有子串的 slice
strings.Fields(s string) []string
sli := strings.Fields("I love beijing")
/*输出:[I love beijing]*/
用 sep 把 a 中的所有元素链接起来
strings.Join(a []string,sep string) string
str := strings.Join([]string{"I", "love", "beijing"}, "@")
/*输出:I@love@beijing*/
func Split(s, sep string) []string //以sep分割
https://www.cnblogs.com/endurance9/p/10336372.html
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter02/02.1.html
常用的string函数https://learnku.com/articles/43150
还有一部分内容:
https://www.cnblogs.com/erenming/p/12072949.html