
Go 里 string 不能直接用索引反转,因为它是 UTF-8 编码的字节序列
Go 的 string 底层是只读的 []byte,但中文、emoji 等 Unicode 字符占多个字节。直接按字节反转(比如 s[i], s[j] = s[j], s[i])会把 UTF-8 编码撕开,产生乱码或 panic。
- 常见错误现象:
invalid operation: cannot assign to s[i](string不可寻址)或输出类似"\u00e9\u0097\u00b4"的非法码点 - 正确做法:先转成
[]rune,再反转 ——rune对应 Unicode 码点,一个中文字符就是一个rune - 性能影响:转换过程涉及内存分配和遍历,对超长字符串(如 MB 级日志)需注意;短字符串(
用 for + []rune 实现安全、可控的反转
这是最常用也最易理解的方式,适合绝大多数场景,包括含 emoji、中日韩文字、组合字符(如带声调的字母)的字符串。
- 不要用
strings.Split或strings.Builder拼接反转 —— 多余分配,且不解决编码问题 - 关键步骤:先
runes := []rune(s),再双指针交换,最后string(runes)转回 - 示例:
func reverseString(s string) string { runes := []rune(s) for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { runes[i], runes[j] = runes[j], runes[i] } return string(runes) }
需要高性能?避免分配时考虑 unsafe.String(Go 1.20+)
如果确定输入全是 ASCII(比如纯英文 token、base64 片段),且已做校验,可以跳过 []rune 转换,直接操作字节并用 unsafe.String 构造结果 —— 节省约 30% 分配开销。
- 适用场景:内部服务间固定格式字段、HTTP header 值、UUID 反转等 ASCII-only 数据
- 风险点:一旦混入非 ASCII 字符,结果不可预测;
unsafe代码需严格测试,上线前加for _, r := range s { if r > 127 { panic("non-ASCII") } }校验 - 参数差异:
unsafe.String第二个参数必须是已知长度的[]byte,不能传string字面量地址
别忘了边界情况:空字符串、单字符、含零宽连接符(ZWJ)的 emoji
像 "??" 这类合成 emoji 是多个 Unicode 码点通过 ZWJ 连接而成,[]rune 反转后顺序错乱,显示为分离的 ? + ?,失去语义。
立即学习“go语言免费学习笔记(深入)”;
- 这不是 Go 的 bug,是 Unicode 规范限制 —— 目前没有标准 API 能“智能”识别合成字符簇(grapheme cluster)
- 若业务强依赖 emoji 完整性(如社交评论处理),得引入第三方库如
github.com/rivo/uniseg按字形切分,再反转 - 容易被忽略的点:测试用例只覆盖
"hello"和"你好",漏掉"?❤️??"这类 7 个rune的字符串,上线后才发现反转异常










