Golang中的rune数据类型介绍和使用
Go 中比较常见的 int、string、bool、float 基本数据类型之外还有其他的数据类型可以应用在特殊场景,比如 rune 就是类似于 int32,因为其可表示的字符范围更大,实际工作中可以用来计算字符串的真实长度
关于 rune
rune 类型的官方解释如下:
// 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.
type rune = int32
rune 是 int32 的别名,几乎在所有方面等同于 int32,它用来区分字符值和整数值。
仅仅看这段描述并不能看出 rune 类型的特殊之处。
应用 rune
通过一段代码来尝试以下,看看 rune 的特别之处。
func main() {
str := "米虫 is cool"
fmt.Println("STR LEN - ", len(str))
}
上文代码中 str 字符串的长度输出会是多少呢?2 个汉字 2 个空格 6 个字母。
STR LEN - 14
输出的结果并不是预想中的 10 位。
原因是在 Go 中 string 的底层是通过 []byte 来实现的。
其中中文在 Unicode 编码中是占用 2 个字节,在 utf-8 编码下占用 3 个字节,因此 2 个汉字=6 个字节,长度为 6+2+6=14。
但是如果我们希望获得准确的字符长度呢?总不能自行去判断字符的类型进行加减乘除吧。
utf8 包
第一种方案是,通过 Go 的 RuneCountInString() 函数取得真实的字符串长度。
func main() {
str := "米虫 is cool"
fmt.Println("STR LEN - ", utf8.RuneCountInString(str))
}
这个函数内部实际就是遍历整个字符串,判断字符所在的区域从而动态的将指针后跳 +1+2+3,最后计算出真实的长度。
emm...虽然是 API 函数,但是总觉得不够优雅。
[]rune
第二种方案就是通过 []rune 来接收字符串,代码如下:
func main() {
str := "米虫 is cool"
fmt.Println("STR LEN - ", len([]rune(str)))
}
可以理解为将 str 转为 []rune 数组,然后计算 []rune 数组的长度即可。
rune 和 byte
我们前面提到,string 在底层默认通过 []byte,在 Go 中 byte 和 rune 的区别是什么?
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8
// 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.
type rune = int32
rune 和 byte 非常类似,都是可用来表示字符类型的变量类型:
- byte 等同于 int8,(-128~127)用来表示 ascii 字符,因为 ascii 字符一般就占用一个 byte。
- rune 等同于 int32,(-2^31~2^31-1)用来表示 unicode 或 utf-8 字符,因为 rune 更大,可能容纳表示更多范围的字符。
因为 byte 数字范围较小,所以用来表示中文字符的时候,utf-8 需要使用 3 个 byte。
