string
要解释rune类型,我们先要了解string类型。
string 类型的本质是一连串8个bit的字节, string 字符串可以直接转换成[]byte类型
s := "abc"
fmt.Println([]byte(s))
// output
// [97 98 99]
复制代码
以上代码打印了字符在ascii 编码表中的编号。
当然,不仅可以打印字符编号,也可以直接打印相应的字符
s := "abc"
for _, v := range []byte(s) {
fmt.Printf("%c, %v\n", v, v)
}
// output
// a, 97
// b, 98
// c, 99
复制代码
我们可以说, string类型本质上就是一组字节组成的数组([]byte)。
Golang 源码本身使用的是UTF-8编码(非utf-8格式的源码不能编译),除了ascii,golang 也可以打印Unicode的字符编码,
for _, v := range "汉字" {
fmt.Printf("character %c,unicode %U \n", v, v)
}
// output:
// character 汉,unicode U+6C49
// character 字,unicode U+5B57
复制代码
Unicode 和 UTF-8
要了解rune,我们还需要了解unicode和utf8
Unicode和 UTF-8的关系:
- Unicode 是一个编码表,在v13.0版本中,拥有143,859 个字符.
- UTF-8 是一种对Unicode 的编码方式.
- UTF-8 对一个字符使用1-4个字节进行编码.
这张图展示了UTF-8的编码规则
-
Code point(码点),也就是字符在unicode 中对应的编号。
-
使用一个字节编码的码点范围是0~7F, 对应的十进制就是0-127. 这里完全兼容了ascii编码表.
-
使用两个字节编码的码点范围是80-7FF, 对应的十进制就是128-2047。这部分主要是一些拉丁文
-
中文的码点范围是4E00-9FFF, 共计20992个字符,对应着编码规则的第三条,使用3个字节进行编码.
有兴趣的可以看看unicode 编码表unicode-table.com/en/blocks/
rune
了解了string, 以及unicode, utf8编码之后,我们现在可以来讨论什么是rune 类型了, 以及为什么要有rune类型。
先来看一段代码:
chinese := "汉字"
fmt.Printf("length: %d\n", len(chinese))
复制代码
你们觉得结果是什么?
答案居然是6?
length: 6
复制代码
为什么长度是6?
文章开头我们说过,string类型的本质就是[]byte,底层使用byte来表示对应的字符。
len(string) 表示字符串的字节长度
在UTF-8编码规则中,一个中文占3个字节,“汉字” 这两个中文的长度就是6了
那我们该怎么统计正确的中文长度呢?
现在把字符串转换成rune类型试一下
chinese := []rune("汉字")
fmt.Printf("length: %d\n", len(chinese))
// output
// length: 2
复制代码
这次的结果是2,正确的得出了字符的长度。
现在我们知道,rune 的值表示字符的码点,而码点就是unicode 中字符的编码。
将string 转换成rune类型的同时,就是将UTF8编码的字符,变成了一个个码点(code-point)
range string
再来看一下上面那个例子, 这次我们把它的索引打出来.
for i, v := range "汉字" {
fmt.Printf("character %c,value %d,unicode %U position %d\n", v, v, v, i)
}
// output:
// character 汉,value 27721,unicode U+6C49 position 0
// character 字,value 23383,unicode U+5B57 position 3
复制代码
在对string循环的时候,是比较特别的。因为index并不等于字符在string中的位置,而是对应着字符在string中byte的起始位置.
总结
rune 是golang中的一种数据类型,底层类型是int32,用来存储unicode code-point.
type rune = int32
复制代码
近期评论