Go中无substring函数,字符串截取需用切片语法s[start:end],但按字节操作易致UTF-8乱码;安全截取中文/emoji须先转[]rune再切片,否则可能panic。

Go 里用 substring 会报错,因为压根没这个函数
Go 没有 substring、substr 或 slice 这类字符串方法。所有“截取”操作都靠切片语法 s[start:end] 完成,本质是操作底层字节序列——所以中文等 UTF-8 字符容易越界或截断乱码。
- 直接写
s[2:5]是按字节索引,不是按字符(rune) - 如果字符串含中文、emoji,
s[1:4]可能切在某个汉字中间,导致invalid UTF-8 sequence - 索引超出长度会 panic:
panic: runtime error: slice bounds out of range - 空字符串或 nil 字符串不能直接切,需先判空
按字符(rune)安全截取:必须先转 []rune
要真正按“第几个汉字”来截,得先把字符串转成 []rune,再切片,最后转回 string。这是唯一稳妥方式,但有性能开销——每次转换都要遍历整个字符串做 UTF-8 解码。
-
rs := []rune(s)是必要前置步骤,别跳过 - 截前 3 个字符:
string(rs[:min(3, len(rs))]),记得防越界 - 从第 2 个字符起取 4 个:
string(rs[2:min(2+4, len(rs))]) - 不要用
len(s)判断字符数,它返回的是字节数;用len([]rune(s))
用 strings.IndexRune 或 strings.SplitN 做语义化截取
如果目标不是“前 N 个字符”,而是“截到第一个冒号之前”或“取第二段用下划线分隔的内容”,硬算 rune 索引反而绕路。这时该用 strings 包的语义函数。
- 找位置后切:
pos := strings.IndexRune(s, ':'); s[:pos](注意检查pos == -1) - 按分隔符拆:
parts := strings.SplitN(s, "_", 3); parts[1]更直观可靠 -
strings.TrimPrefix/TrimSuffix适合固定前缀/后缀场景,比手动算索引干净 - 避免反复调用
strings.Index+ 切片拼接,性能差且易出错
边界情况:空字符串、nil、超长索引、BOM 头
线上真实数据常带干扰项。比如读文件时开头有 UTF-8 BOM(\uFEFF),或 HTTP 返回空响应体,或日志字段为 nil(指针未初始化)。这些不处理,一上线就 panic。
- 统一用
if s == ""判空,Go 中字符串零值就是"",不会是nil - 但如果你接收的是
*string,就得先判指针:if s == nil || *s == "" - BOM 头可用
strings.TrimPrefix(s, "\uFEFF")清理,别依赖切片位置 - 计算索引前务必比较:
if start > len(rs) { start = len(rs) },别信外部输入
事情说清了就结束。最常被忽略的其实是 rune 转换那一步——很多人图快直接字节切,本地测试全英文没问题,一上生产遇到用户昵称里的 emoji 就崩。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











