Go中的rune
rune类型是文字符号,它是int32类型的别名。
刚开始看到Go的rune类型的时候,我感到很迷惑,在JavaScript和Python中,字符就是字符,整数就是整数,但是在Go中,rune表示文字字符,却又是int32类型的别名。
仔细了解后就会觉得合理了,先从字符编码的方式开始说起:
一开始计算机使用的是ASCII码,ASCII码用7位表示128个字符,包含英文字母,标点符号和数字等:
(图片来源:ASCII码对照表)
显然,ASCII码并不能表示除了英语之外的其他语言,比如中文,所以Unicode编码出现了,它整理、编码了世界上大部分的文字系统。Unicode至今仍在不断增修,每个新版本都加入更多新的字符。
Go的代码使用的是UTF-8的编码方式。UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字元编码,它可以用一至四个字节对Unicode字符集中的所有有效编码点进行编码:
UTF-8 | 所需字节 | 注释 |
---|---|---|
0zzzzzzz(00-7F) | 1个字节 | ASCII字元范围,位元组由零开始 |
110yyyyy(C0-DF) 10zzzzzz(80-BF) | 2个字节 | 第一个位元组由110开始,接著的位元组由10开始 |
1110xxxx(E0-EF) 10yyyyyy 10zzzzzz | 3个字节 | 第一个位元组由1110开始,接著的位元组由10开始 |
11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz | 4个字节 | 将由11110开始,接著的位元组由10开始 |
使用ASCII码的时候,所有的字符都可以用1字节就能表示,但是使用UTF-8编码的时候,有的字符不止有1字节。
接下来进行一个小练习,打印出字符串中的单个字符。
注意,Go中的len方法返回的是字符串的字节数,不是包含的字符的数量。
- 打印只包含英文字母和数字的字符串中的字符:
s1 := "abc123"
for i := 0; i < len(s1); i++ {
fmt.Printf("%c\n", s1[i])
}
打印结果:
a
b
c
1
2
3
- 打印包含中文的字符串中的字符:
s2 := "a写点啥"
for i := 0; i < len(s2); i++ {
fmt.Printf("%c\n", s2[i])
}
打印结果:
a
å
ç
¹
å
¥
除了a是正常打印出来的,中文打印的都是奇怪的符号。因为是一字节一字节的取值,取的位置不对,所以打印的结果不正确,稍微修改下打印语句,把取到的值的二进制数字也打印出来:
s2 := "a写点啥"
for i := 0; i < len(s2); i++ {
fmt.Printf("%c %[1]b \n", s2[i])
}
可以看出“写”,“点”,“啥”每个Unicode码占用的是3字节,而不是1字节,所以取到的值有问题。要正常打印出值,应该分别这样取值:
fmt.Printf("%c\n", s2[0])
fmt.Printf("%v\n", s2[1:4])
fmt.Printf("%v\n", s2[4:7])
fmt.Printf("%v\n", s2[7:10])
打印结果:
a
写
点
啥
遍历的时候需要先得到字符占用的字节数量,然后根据占用的字节数量取到对应的值,这很不方便。
使用rune类型的话,不论这个字符占用的是几字节,它都表示一个字符。
s2 := "a写点啥"
s3 := []rune(s2)
fmt.Println(len(s2)) // 10
fmt.Println(len(s3)) // 4
for i := 0; i < len(s3); i++ {
fmt.Printf("%c\n", s3[i])
}
打印内容:
10
4
a
写
点
啥
rune类型是 用于表示字符的Unicode代码点的int32整数的类型, 所以它表示的是文字符号的类型。
另外,如果只是想要遍历字符的话,可以直接用range:
s4 := "a写点啥"
for i, value := range s4 {
fmt.Printf("%d %c\n", i, value)
}
打印内容:
0 a
1 写
4 点
7 啥
参考地址
转载自:https://juejin.cn/post/7173133571266347039