字符串的定义与底层结构
字符串(string)是 Go 语言中的基础数据类型,可以看成是由一个个字符组成的数组,但其实 string 底层的数据是使用字节数组存储的。
可以使用双引号 "" 或者反引号 `` (键盘中Tab上面的那个按键)来声明字符串。
var s string = "DawnSiro"
var ss string = `Dawn
Siro`
其中,双引号声明的字符只能声明单行,且如果字符串的内容中包含了双引号的话,需要使用 \ 来进行转义。
json := "{"id":1}"
而反引号声明的字符串就可以声明多行,而且包含双引号的情况下无需转移,在需要手写JSON字符串的时候还是比较好用的。
json := `{
"id" : 1
}`
"hello"
reflect.StringHeader
type StringHeader struct {
Data uintptr
Len int
}
其中,Data 为指向底层实际存储 string 数据的只读字符数组,Len为数组的长度。
常见操作
获取字符串长度
len()
s := "DawnSiro"
fmt.Printf("len(s): %v\n", len(s)) // len(s): 8
注意这里的 Len 并不是指字符的长度,而是数组的长度。
在 Go 语言中使用的是 UTF8 对字符串进行编码。
在 UTF-8 编码中,中文字符通常占用 3 个字节。这是因为中文字符使用了 Unicode 的 3 字节编码范围,即 U+0800 到 U+FFFF 之间的编码。
另外,UTF-8 编码中的每个字符可能会占用不同数量的字节。例如,英文字符通常只需要占用 1 个字节,而某些特殊字符可能需要占用多达 4 个字节。
ss := "晓希洛"
fmt.Printf("len(s): %v\n", len(ss)) // len(s): 9
这个例子中的字符串只有三个中文字符,而该字符串的 Len 却是 9 。
访问字符串中的字符
Go语言中的字符串是一个只读的byte类型的切片。
所以可以直接使用类似数组下标访问的方法进行访问
s := "DawnSiro"
fmt.Printf("s[0]: %v\n", s[1]) // s[1]: 97
s 的 1 号索引位置的字符是 a,使用 byte 表示为 97 。
当然因为字符串底层是只读数组的缘故,是无法对字符串中的字符进行修改的。
s[1] = 'A'// cannot assign to s[1] (value of type byte)
另外需要说明的是,字符串的只读仅限于底层数组的数据和长度不能改变,string 类型的指向还是可以改变的。
s := "Dawn"
fmt.Printf("s: %v\n", s) // s: Dawn
s = "Siro" // 改变了 s 的指向
fmt.Printf("s: %v\n", s) // s: Siro
遍历字符串
字符串可以通过下标直接访问对应位置的字符,我们很自然的可以想到使用 循环 + 遍历索引下标的方式。
s := "DawnSiro"
for i := 0; i < len(s); i++ {
fmt.Printf("%c", s[i])
}
// DawnSiro
但是前面也说过,string 中的长度和字符数可能不是对应的,因为有的字符串可能需要多个字节来表示。
s := "晓希洛"
for i := 0; i < len(s); i++ {
fmt.Printf("%c", s[i])
}
上面的代码就只会打印出乱码了。
那么该怎么遍历带有需要多个字节的字符的字符串呢?
最简洁的方式是使用 for range 循环。
for i, v := range s {
fmt.Printf("%v ", i)
fmt.Printf("%c\n", v)
}
/*
0 晓
3 希
6 洛
*/
第一个参数i是该字符的启示下标,第二个参数是表示该字符的符文数 rune。
那么什么是符文数呢?我们看看官方给出的解释。
type rune = int32
rune is an alias for int32 and is equivalent to int32 in all ways. It is used, by convention, to distinguish character values from integer values.
我们简单翻译下第一句话:符文数是int32的别名,在所有方面都与int32等效。
所以符文数其实就是使用一个 int32 来表示字符。
为什么可以这样表示呢?
这是因为UTF-8编码最多占四个字节,使用同为四个字节的 int32 完全能够表示了。
字符串与字节数组的转换
直接使用强转的写法就能进行转换了。
str := "hello"
charArr := []byte(str)
str = string(charArr)
字符串拼接
Go 语言中可以直接使用加号 + 进行字符串之间的拼接。
s := "a" + "b"
fmt.Printf("s: %v\n", s)
但需要注意的是,字符串和其他数据类型之间并不能使用 + 直接进行拼接。
ss := "a" + 1 // invalid operation: "a" + 1 (mismatched types untyped string and untyped int)
fmt.Sprintf()
s := "a" + "b"
fmt.Printf("s: %v\n", s)
s1 := fmt.Sprintf("%s %d", s, 1)
fmt.Printf("s1: %v\n", s1)
比较和搜索
Go 语言中的字符串可以直接使用 == 进行比较。
另外使用双引号和反引号声明的字符串被认为是同一内容的字符串。
if "ss" == `ss` {
fmt.Println("对的")
} // 对的