应优先用 range 遍历字符串,因其自动解码 utf-8 返回完整 rune;下标访问 s[i] 返回 byte,易将多字节字符(如中文、emoji)错误拆分;截取或统计字符数时须转 []rune,长度判断应使用 utf8.runecountinstring() 而非 len()。

字符串遍历时用 range 还是下标访问?
用 range 得到的是 rune,用 s[i] 得到的是 byte——这是最常踩坑的起点。
- 中文、emoji、日文等 UTF-8 多字节字符,用下标遍历会把一个字符拆成多个
byte,比如"你好"[0]是228(你的第一个 UTF-8 字节),不是完整字符 -
range自动解码 UTF-8,每次迭代返回一个完整的 Unicode 码点,for _, r := range "你好" { fmt.Printf("%c", r) }输出“你好”,不会乱码 - 想按“字符位置”截取前 2 个汉字?不能写
s[:4](那是前 4 字节,可能只截出半个“你”),得先转[]rune(s)[:2]再转回string
统计长度该用 len() 还是 utf8.RuneCountInString()?
len(s) 返回字节数,utf8.RuneCountInString(s) 才是真实字符数——尤其处理用户输入或国际化文本时,错用就翻车。
-
len("嗨") == 3(UTF-8 编码占 3 字节),但人眼只看到 1 个字符 - 表单校验限制“最多 10 个字符”?用
len()会让用户输 3 个中文就报超限;必须用utf8.RuneCountInString(s) - 性能上,
utf8.RuneCountInString()需扫描整个字符串,若已转过[]rune,直接用len([]rune(s))更快(但注意内存开销)
什么时候该用 []byte,什么时候必须转 []rune?
操作原始数据流(如网络包、文件头)用 []byte;操作人类可读文本(尤其是含中文/emoji)必须用 []rune。
- 拼接字符串频繁?别用
+=,改用bytes.Buffer或预分配[]byte,避免重复分配 - 反转字符串?
for i, j := 0, len(s)-1; i 直接交换 <code>s[i]和s[j]会破坏 UTF-8 结构;正确做法:r := []rune(s); for i, j := 0, len(r)-1; i - 正则匹配、JSON 解析等标准库函数内部已处理 UTF-8,通常不用手动转
rune;但自定义逻辑(如取第 N 个字符、按字符切分)绕不开[]rune
类型混淆导致的典型 panic 或静默错误
Go 不会在编译期报 byte 和 rune 混用错,但运行时行为诡异——比如字符串比较失真、索引越界、或看似正常却漏掉半个 emoji。
- 错误写法:
var c byte = '中'→ 编译失败('中'是rune,值为20320,超出byte的 0–255 范围) - 危险写法:
b := []byte("??"); fmt.Println(len(b))输出11(emoji 组合字符 UTF-8 占 11 字节),但人眼只认作 1 个角色 - 静默陷阱:
s := "a你"; fmt.Println(s[1])打印228(你的首字节),如果误以为这是字符 '你' 的 ASCII 码,后续逻辑全偏移
真正难的不是记定义,而是每次拿到字符串时下意识问一句:我是在跟字节打交道,还是在跟字符打交道。一念之差,len 就差三倍,index 就越界,reverse 就变乱码。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











