Go语言中常见100问题-#36 rune使用分析

前言

本文讨论rune相关知识,在深入讨论前,我们需要理解字符和编码的区别:

  • 一个字符,正如其名,表示字符集合中的一个元素,例如,Unicode字符集包含2^21个字符
  • 编码是将字符表用二进制来表示。例如,UTF-8是一种编码标准,将Unicode字符集用一种可变长的字节数组表示(1到4个字节)

通过字符可以简化字符集定义,但是在Unicode中,使用代码点来标识字符,字符集中的每个字符都有唯一的代码点值。例如,中文汉字的代码点值是U+6C49. 如果采用UTF-8编码,汉字存储占3个字节:0xE6,0xB1,0x89. 理解这些非常重要,因为在Go语言中,1个rune字符是一个代码点。

rune使用分析

我们知道UTF-8编码会将一个字符编码为1到4个字节,4字节也就是32比特。所以在Go语言中,rune被定义为int32的别名。

go 复制代码
type rune = int32

还有一点需要强调,有些人认为Go字符串都是UTF-8, 事实并不是这样。通过下面的例子进行说明,下面程序将hello字符串赋值给变量s, 在Go中,源代码被编码为UTF-8. 因此,所有字符串文字都使用UTF-8编码为字节序列。但是,字符串是任意字节的序列:不一定基于UTF-8, 例如从文件系统中读取的内容,我们不能假定它一定使用的是UTF-8编码后的字节序列。

golang 复制代码
s := "hello"

NOTE golang.org/x 扩展了标准库功能,为我们提供了操作UTF-16和UTF-32相关功能包

回到上述代码,字符串hello由五个字符:h,e,l,l,o构成。这些都是简单字符,每个字符编码为1个字节。所以字符串s的长度为5.

golang 复制代码
s := "hello"
fmt.Println(len(s)) // 5

注意,并不是每个字符都是编码成1个字节,例如中文汉字,因为采用UTF-8编码,会被编码为3个字节,下面程序输出变量s的长度为3,而不是1.

golang 复制代码
s := "汉"
fmt.Println(len(s)) // 3

为啥len函数返回的是3而不是1呢?因为len是一个内置函数,它返回的不是字符串中字符的个数,而是字符串编码后的字节数。

因此,我们可以通过字节切片构造字符串。前面提到,汉字符被编码为 0xE6、0xB1和0x89三个字节。创建字符串s通过3个字节构成,打印输出的内容为中文汉字。

golang 复制代码
s := string([]byte{0xE6, 0xB1, 0x89})
fmt.Printf("%s\n", s)

思考总结

  • 字符集是一组字符,字符编码描述了如何将一个字符转换成二进制
  • 在Go中,字符串底层切片是不可修改的
  • Go源代码使用UTF-8编码,因此编码后的所有字符串都是UTF-8存储。但是从文件系统中读取到的字符串不一定是UTF-8编码
  • rune对应一个Unicode中的码点,每个Unicode字符表示为单个rune值
  • 采用UTF-8编码,Unicode字符集被编码为1到4个字节
  • Go中,len函数返回的是字符串的存储的字节数,而不是字符的个数
相关推荐
ssshooter9 分钟前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友14 分钟前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry1 小时前
Jetpack Compose 中的状态
前端
David爱编程2 小时前
面试必问!线程生命周期与状态转换详解
java·后端
dae bal2 小时前
关于RSA和AES加密
前端·vue.js
柳杉2 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化
lynn8570_blog2 小时前
低端设备加载webp ANR
前端·算法
LKAI.2 小时前
传统方式部署(RuoYi-Cloud)微服务
java·linux·前端·后端·微服务·node.js·ruoyi
Victor3562 小时前
Redis(11)如何通过命令行操作Redis?
后端
Victor3562 小时前
Redis(10)如何连接到Redis服务器?
后端