在 Golang 中,字符串(string)和字符(rune)是两个不同的概念:
- 字符串(string)是一个字节序列,可以包含任何二进制数据。每个字符串由一个不可变的字节数组表示。
- 字符(rune)是一个 Unicode 码点,代表一个 Unicode 字符。rune 是 int32 的别名。
也就是说:
- string 表示文本序列,是以字节为单位的。
- rune 表示 unicode 字符,是以字符为单位的。
例如:
s := "Hello" // s的类型为string
c := 'H' // c的类型为rune,等价于int32
由于 Golang 支持 Unicode,所以一个字符不一定占用一个字节:
s := "你好"
for i := 0; i < len(s); i++ { // len(s) = 6
c := rune(s[i])
fmt.Printf("%c %d\n", c, c)
}
// 你 20320
// 好 22909
可以看到,中文字符你和好都占3个字节,对应一个rune值。
所以当我们需要以字符为单位处理文本时,应使用rune,其他大部分场景使用string即可:
// 字符串遍历
for i := 0; i < len(s); i++ { // byte为单位
fmt.Printf("%c", s[i])
}
// 字符遍历
for _, c := range []rune(s) { // char为单位
fmt.Printf("%c", c)
}
字符串相关的内建函数大多数针对的都是byte,而不是char,所以需要自行处理字符的rune值。
例如:
- len():返回字符串的byte数,而不是字符数
- cap():返回字符串的底层数组的cap,以byte为单位
- 加法拼接字符串:实际是字节序列的拼接
所以,掌握字符串和字符的差异以及处理方式对 Golang 开发者来说是比较重要的。特别是在处理 Unicode 文本及其他语言时,这一点就尤为关键。
需要注意的是,大部分情况下我们可以简单地把字符串当作字符序列来处理,不过一旦需要精确地操作字符,则必须转为 rune 数组或切片后再行处理。