本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1、字符串本质
字符串的本质是一个字符数组,其结构如下所示:
type StringHeader struct {
Data uintptr // 指向底层字符数组
Len int // 字符数组的长度
}
💡 字符串常量存储于静态存储于,无法被修改
Go语言中使用的是UTF-8字符集,这是一种长度不固定的编码方式,也就是有不同的字符,所占用的字节数可能不一样,下面是示例:
图解:
代码:
func test() {
// 使用UTF-8编码,英文占1个字节,中文占3个字节
str1 := "GoGoGo"
str2 := "Go语言"
fmt.Println(len(str1)) // 6
fmt.Println(len(str2)) // 8
// range操作中的index是字符在数组中的偏移量
for index, c := range str2 {
fmt.Printf("%#U starts at byte position %d\n", c, index)
}
// 输出:
// U+0047 'G' position is 0
// U+006F 'o' position is 1
// U+8BED '语' position is 2
// U+8A00 '言' position is 5
}
2、Rune类型
在Go语言中,由于不同的字符所占字节大小可能不同,为了区分字符,使用rune类型来表示单个字符,其本质上其实是int32,用于区分字符值与整数值
type rune = int32
因此,在对字符串使用range操作时,遍历的并非字是单个字节,而是rune,在使用下标对字符串进行操作时其实也是在操作字符数组
3、字符串解析
字符串在声明时既可以使用``也可以使用",两者的区别在于,前者不会对\进行特殊处理,如下所示:
func test() {
rowStr := `\123\t\321`
normalStr := "\t\123"
fmt.Println(rowStr) // 输出: \123\t\321
fmt.Println(normalStr) // 输出: S
}
4、字符串拼接
在Go语言中,字符串可以使用操作符+对字符串进行拼接
func test() {
str1 := "hello " + "world" // 在编译时完成
str2 := str1 + "a" // 在运行时完成
fmt.Println(str2)
}
在运行时进行字符串拼接的过程如下:
- 判断拼接后的字符串是否大于32字节
- 如果小于32字节则使用临时的缓存
- 如果大于32字节则在堆中开辟一个新的内存空间
- 然后将待拼接的字符串复制到新数组中(内存复制)