rune代表Unicode码点(逻辑字符),byte代表单字节(0–255);处理文本应优先用rune,协议或二进制操作用byte;含非ASCII字符时切片/索引必须转[]rune,避免截断。

Go语言中,rune和byte看似都是整数类型,但语义完全不同:前者代表Unicode码点(即“字符”的逻辑单位),后者仅代表一个字节。搞混它们是字符串处理出错的常见原因。
byte 是 uint8,只管单个字节
byte 是 uint8 的别名,取值范围 0–255,它不关心编码,只负责存储原始字节数据。在 ASCII 范围内(0–127),一个 byte 往往对应一个可读字符;但一旦涉及中文、emoji 或带重音的字母(如 é),单个 byte 就无法表示完整字符了——因为 UTF-8 是变长编码。
- 字符串字面量底层是字节数组,
len("你好")返回 6(每个汉字占 3 字节) - 用索引访问:
"你好"[0]拿到的是第一个字节(0xe4),不是“你”这个字符 - 循环遍历字符串时,
for i := range s中的i是字节偏移,不是字符位置
rune 是 int32,代表一个 Unicode 码点
rune 是 int32 的别名,用来明确表达“我这里存的是一个逻辑字符”。要得到字符串中的 rune 序列,必须显式转换:
-
runes := []rune("Hello 世界?")→ 长度为 9(H/e/l/l/o/空格/世/界/?) -
for _, r := range "Hello 世界?"—— 这个range自动按 rune 解码,r就是当前字符的码点 -
fmt.Printf("%c %U\n", r, r)可同时打印字符和 Unicode 编码(如世 U+4E16)
什么时候该用 byte,什么时候该用 rune?
选型关键看操作对象:如果处理协议、文件头、网络包或做字节级校验,用 byte;如果要做文本分析、截断、计数、大小写转换、正则匹配,必须用 rune。
立即学习“go语言免费学习笔记(深入)”;
- 提取前 3 个字符?→
string([]rune(s)[:3]),不能用s[:3](可能截断汉字) - 统计字符数(非字节数)?→
len([]rune(s)) - 判断是否为英文字母?→
unicode.IsLetter(r)(参数是 rune) - 拼接二进制数据?→ 用
[]byte,比如append([]byte("hello"), 0x00, 0xff)
常见坑与快速自查
很多 bug 来自把字符串当字节数组直接切片或索引。一个简单自查方法:只要你的字符串可能含中文、日文、emoji、áéíóú 或任何非 ASCII 字符,就别用 len(s) 或 s[i] 做“字符”相关计算。
- 错误示例:
s := "Go编程"; fmt.Println(s[2])→ 输出 177(字节),不是“编”的首字节 - 正确做法:
r := []rune(s); fmt.Printf("%c", r[2])→ 输出 “编” - 性能提示:转
[]rune会拷贝整个字符串并解码,高频场景可考虑用strings.Reader或utf8.DecodeRuneInString流式处理
基本上就这些。记住一句话:byte 是存储单位,rune 是语义单位。该解码的时候别省那一次转换。










