深色模式
Go语言之 rune 类型
概述
Go 里一旦开始处理文本,byte、rune、string 这三个名字几乎绕不过去。它们经常一起出现,也经常被误当成同一层概念。真正的区别是:string 表示一段字节序列,byte 更接近原始字节,rune 则用来表示一个 Unicode 码点。
如果这层没分开,很多现象都会显得古怪:为什么 len("中") 不是 1,为什么 for range 和按字节下标遍历结果不同,为什么一个字符不一定对应一个字节。
rune 本质上是 int32 的别名
go
type rune = int32这意味着:
rune不是新定义类型- 它和
int32是同一个类型 - 它存在的主要价值是表达语义,而不是引入新规则
一个 rune 表示一个 Unicode 码点
这句话比“一个 rune 表示一个字符”更准确。
因为 Unicode 文本里,用户眼里的“一个字符”不一定总是单个码点组成。但在 Go 里,rune 讨论的是码点这一层。
byte、rune、string 分别站在哪一层
可以先这样理解:
| 名字 | 更接近什么 |
|---|---|
byte | 单个字节 |
rune | 单个 Unicode 码点 |
string | 一段只读字节序列 |
len(string) 数的是字节,不是 rune 数量
例如:
go
s := "中"
fmt.Println(len(s))结果通常不是 1,而是 3,因为 UTF-8 编码下这个字符占 3 个字节。
for range 遍历字符串时拿到的是 rune
例如:
go
for i, r := range "Go众" {
fmt.Println(i, r)
}这里:
i是当前码点起始位置对应的字节下标r是当前解码出来的rune
rune 字面量写法
最常见的是直接写单引号字符:
go
'a'
'π'
'众'还可以写成转义形式:
go
'\141'
'\x61'
'\u0061'
'\U00000061'这些写法和 'a' 表达的是同一个码点值。
什么时候该显式用 rune
通常是这几类场景:
- 明确在处理 Unicode 码点
- 需要按字符级语义遍历文本
- 需要把字符和整数值之间做显式转换
最容易混的点
rune 不是“Go 版字符类型”
更准确地说,它是 Unicode 码点表示。
string 不是 []rune
string 的底层语义更接近只读字节序列。需要按码点处理时,通常要显式转换或用 range 解码。
一个字符不一定等于一个字节
这正是 byte 和 rune 必须分开的原因之一。
一条够用的判断线
处理文本时,先问自己:
- 当前要按字节处理,还是按 Unicode 码点处理。
- 当前拿到的是原始字符串,还是已经解码后的字符单位。
- 这里更适合
byte、rune,还是直接保留string。
