for range 遍历字符串时按 rune 拆分,中文不会乱码;「北京」被正确识别为两个 rune,索引与值一一对应,避免了按字节遍历导致的乱码问题。

用 for range 遍历字符串,中文不会乱码
Go 的 for range 遍历字符串时,自动按 rune(Unicode 码点)拆分,不是按字节。这意味着「北京」两个汉字会被正确识别为两个独立字符,索引和值一一对应。
常见错误现象:有人写 for i := 0; i 然后取 <code>str[i],遇到中文就输出乱码或截断——因为 len() 返回的是字节数,而一个中文占 3 字节,str[6] 可能只是「北」的第二个字节。
-
range返回的index是该字符在字符串中的起始字节位置(不是第几个字符),比如"你好"中「好」的index是 3 -
val类型是rune(即int32),不是byte,所以fmt.Printf("%c", val)能正常打印中文 - 不需要手动转
[]rune,range已内置 UTF-8 解码逻辑
什么时候必须转成 []rune?
只有当你需要「按字符序号索引」或「修改/重排字符顺序」时,才需要显式转切片。因为字符串本身不可变,且原生不支持下标取「第 N 个字符」。
使用场景举例:提取第 3 个汉字、反转字符串、去重相邻字符等。
-
str := "hello北京"→runeSlice := []rune(str)后,runeSlice[5]才是「北」 - 直接
str[5]是字节,可能是乱码;str[6]和str[7]是「北」的后两个字节,单独打印无意义 - 性能影响:转
[]rune会分配新内存,对超长文本(如 MB 级日志)需注意 GC 压力
strings.Map 适合批量字符转换
如果你的目标不是“遍历查看”,而是“把每个字符做统一变换”(比如全转大写、过滤控制符、替换 emoji),strings.Map 比手写循环更简洁安全。
它内部已处理好 UTF-8 边界,你只管写映射函数,不用操心字节 vs rune。
- 函数签名:
func Map(mapping func(rune) rune, s string) string - 例如把所有字母转大写:
strings.Map(unicode.ToUpper, "Hello北京")→"HELLO北京" - 返回新字符串,原串不变;映射函数返回
-1表示删除该字符
别踩这些坑
最常被忽略的其实是「字符串不可变」和「len() 的语义混淆」。这两点叠加,会让新手反复掉进同一个坑里。
- 写
str[0] = 'X'直接编译失败 —— Go 不允许修改字符串字节,必须转[]byte或[]rune再构造新串 -
len("北京") == 6,但字符数是 2;想获取字符长度请用utf8.RuneCountInString(str)或len([]rune(str)) - 用
range遍历时如果只想要字符不要索引,记得写for _, ch := range str,否则变量未使用会触发编译警告
真正复杂的不是语法,而是时刻区分「字节位置」和「字符序号」——只要记住 range 给你的是后者,len() 和下标操作给你的永远是前者,基本就不会错。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











