字符串遍历用for range即可,但需注意rune转换的内存开销、组合字符与emoji的多rune特性、截断应使用text/unicode/norm等库,以及utf-8合法性校验。

字符串遍历直接用 for range 就行,但别用 for i := 0; i
Go 的 string 是字节序列,不是字符数组。用 len(s) 得到的是字节数,不是 rune 数——中文、emoji 等 UTF-8 多字节字符会“被切开”,导致乱码或 panic。
正确做法是用 for range,它自动按 rune 迭代:
for i, r := range s {
fmt.Printf("index %d: rune %U\n", i, r)
}
-
i是该 rune 在字节层面的起始位置(不是序号),r是rune类型值(即 int32) - 想同时拿到“第几个字符”(逻辑序号),得自己维护计数器,比如
idx++ - 如果只想要所有 rune 值、不要索引,写成
for _, r := range s更清晰
需要下标访问中文字符?先转成 []rune,但注意内存和性能
想写 chars[2] 拿第三个汉字?string 不支持直接下标取 rune,必须显式转换:
chars := []rune(s) third := chars[2] // 安全,前提是 len(chars) > 2
- 转换会分配新底层数组,对大字符串(如几 MB 日志)有明显内存和 GC 开销
- 转换后
len(chars)才是“字符个数”,cap(chars)和原 string 无关 - 别写
[]rune(s)[i]这种临时转换 + 下标组合——每次都会新建 slice,能缓存就缓存chars
rune 不是“Unicode 字符”的万能解,遇到组合字符和 emoji 仍要小心
一个用户看到的“字符”,可能由多个 rune 组成:比如带声调的 á 可能是 'a' + '\u0301'(组合用重音符),微信表情 ?? 是 4 个 rune 的 ZWJ 序列。
立即学习“go语言免费学习笔记(深入)”;
-
len([]rune(s))返回的是 rune 数,不是“人眼感知的字形数” - 做截断(如取前 10 个“字符”显示省略号)时,用
golang.org/x/text/unicode/norm或golang.org/x/text/segment更可靠 - 简单场景(如纯中文+ASCII 混排)用
[]rune足够;涉及国际化输入、富文本、昵称截断等,就得上专门的分词库
从 string 到 rune 再到 string,编码细节不能漏
修改 rune 切片后转回 string,本质是 UTF-8 编码过程,通常没问题。但以下情况会出问题:
- 手动构造非法 rune(如
0xd800~0xdfff代理区值),转 string 后变成(U+FFFD 替换符) - 传给 C 函数或 syscall 时,确保最终 string 是合法 UTF-8;可用
utf8.ValidString(s)快速校验 - 读文件或 HTTP body 后得到的 string,如果源编码不是 UTF-8(比如 GBK),先用
golang.org/x/text/encoding转换,再处理 rune —— 否则遍历结果完全不可预测










