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。

更多推荐

章节目录