len() 返回字节数而非字符数,因 Go 字符串是 UTF-8 编码的只读字节切片;判断中文长度需用 utf8.RuneCountInString(),截取应转 []rune 后操作。

len() 返回字节数是 Go 字符串底层设计决定的
Go 的 string 类型本质是只读的 []byte,不携带任何编码元信息。它只是 UTF-8 编码后的字节流,len() 统计的是这个字节流的长度,不是“人眼看到的字符个数”。所以 len("你好") 是 6 —— 每个汉字在 UTF-8 中占 3 字节,2 × 3 = 6。
用 len() 判断中文字符串长度会出什么错
常见错误现象包括:
-
if len(s) > 10 { panic("too long") }:用户输入 4 个汉字(实际 4 个字符)就触发 panic,因为len(s)是 12 -
s[:10]截取:可能卡在某个汉字中间,产生非法 UTF-8,后续fmt.Println或 JSON 序列化时报错或显示 - 光标移动、分页、UI 显示计数全错位:比如前端显示 “已输入 6/10 字”,实际才输 2 个汉字
正确获取“字数”必须用 utf8.RuneCountInString()
要得到 Unicode 码点数量(即真实字符数),必须调用 utf8.RuneCountInString():
import "unicode/utf8" s := "你好,世界!" fmt.Println(len(s)) // 15(字节) fmt.Println(utf8.RuneCountInString(s)) // 7(rune 数,即“字数”)
注意:utf8.RuneCountInString() 是 O(n) 时间复杂度,遍历整个字符串解析 UTF-8;而 len() 是 O(1)。高频计数场景需权衡性能与语义准确性。
截取前 N 个中文字符不能用 s[:n]
直接按字节切片必然破坏 UTF-8 结构。正确做法是转成 []rune 再切:
- 错误:
s[:5]→ 可能截断“你好”的“好”字,输出乱码 - 正确:
string([]rune(s)[:5])→ 先解码为 rune 切片,再取前 5 个,最后转回 string - 注意:如果
n超过实际 rune 数,需先判断utf8.RuneCountInString(s) >= n,否则 panic
真正棘手的地方在于:很多旧逻辑把 len() 当“长度”用,但只要字符串含中文、emoji 或任意非 ASCII 字符,这套逻辑就不可靠——不是 bug,是设计使然,得从第一行处理逻辑开始重审。


















