len函数返回字符串的字节长度而非字符数,因Go字符串底层是[]byte;"你好"在UTF-8中占6字节,故len返回6,而字符数为2。

Go 语言里 len 函数能直接获取字符串长度,但返回的是字节长度,不是字符个数 —— 这是绝大多数人踩坑的起点。
为什么 len("你好") 返回 6 而不是 2
Go 的字符串底层是只读的字节切片([]byte),len 操作的是这个字节序列。中文字符在 UTF-8 编码下占 3 字节,所以 "你好" 实际是 6 个字节。
- ASCII 字符(如
"abc"):1 字节/字符 →len和字符数一致 - 中文、emoji、带重音的拉丁字母(如
"café"):多字节 →len≠ 字符数 - 错误现象:
for i := 0; i 会乱码或 panic,因为按字节索引切进了 UTF-8 中间字节
想数“人眼看到的字符个数”,该用 rune 切片
UTF-8 字符串转成 []rune 后,每个 rune 对应一个 Unicode 码点(即逻辑字符),这时 len 才是真正意义上的“字符长度”。
- 正确写法:
len([]rune("你好")) // 返回 2 - 性能注意:转换过程要遍历整个字符串做 UTF-8 解码,对超长字符串(如 MB 级日志)有开销
- 常见误用:
len(strings.Split(s, ""))—— 效率更低,且对 emoji(如 ?)可能出错(某些 emoji 是多个码点组合)
遍历字符串时别用 for i := 0; i
这种写法本质是按字节遍历,遇到多字节字符就会越界或截断,导致 string(s[i]) 返回非法 UTF-8 或空字符串。
立即学习“go语言免费学习笔记(深入)”;
- 安全做法:用
for _, r := range s—— Go 自动按rune拆分,r是rune类型 - 需要索引?用
for i, r := range s——i是字节偏移量(不是字符位置),r是当前字符 - 反例:
s[0]可以取第一个字节,但不能假设它是完整字符;s[1]对中文可能直接是某个汉字的中间字节
真正麻烦的不是记不住 len 返回字节长度,而是习惯性把字符串当“字符数组”去索引和切片 —— Go 不这么干。只要涉及非 ASCII 文本,就得默认走 []rune 或 range,没得绕。


















