分页必须独立校验 skip 和 end,不能依赖单边切片容错;需先将 skip 归一化为 min(skip, len(s)),再令 end = min(skip+size, len(s)),最后执行 s[skip:end]。

Go 字符串切片本身不 panic 的边界行为(如 s[len(s):] 合法)不能直接套用到分页逻辑中;分页必须独立做 skip 和 end 的双重校验,否则仍会触发 panic: slice bounds out of range。
字符串切片 s[i:] 允许 i == len(s),但不意味着分页安全
这个特性只适用于单边切片表达式,比如 s[5:] 在 len(s) == 5 时返回空字符串。但它不延伸到 s[skip:skip+size] 这类双索引操作——只要 skip + size > len(s),哪怕 skip ,依然 panic。
-
s := "abc",len(s) == 3 -
s[3:] → ""✅ 合法(low == len(s)) -
s[2:5]❌ panic(high = 5 > len(s)) -
s[4:4]❌ panic(low = 4 > len(s))
分页本质是双索引操作,不能依赖单边容错机制。
paginate(s string, skip, size int) string 必须显式截断 end
字符串和切片共享同一套切片语义,所以分页函数对 string 和 []T 应该用相同逻辑。关键不是“能不能”,而是“要不要提前归一化”。
- 先确保
skip不超长:if skip > len(s) { skip = len(s) } - 再算
end := skip + size,并限制上限:if end > len(s) { end = len(s) } - 最后执行
s[skip:end]—— 此时skip ,绝对安全
漏掉任一检查都可能在边界场景崩溃,例如请求第 100 页、每页 10 条,但总长仅 3 条。
泛型分页函数无法自动适配字符串,需单独处理
Go 泛型函数如 func paginate[T any](x []T, skip, size int) []T 不能接收 string,因为 string 不是 []byte 的别名,也不是任意类型切片。你不能写 paginate("hello", 1, 2)。
- 若需同时支持字符串和切片,得写两个重载函数,或统一转成
[]byte(注意 UTF-8 多字节问题) - 更稳妥的做法是:对字符串分页,始终用
string类型参数;对其他数据用泛型切片函数 - 不要试图用
unsafe.String()强转 —— 既破坏类型安全,又在非 ASCII 场景下出错
字符串的不可变性与字节视图的分离,决定了它在分页中必须被当作独立类型对待。
用户输入的 skip 或 为负数时,会静默返回错误结果
标准分页函数通常只处理“过大”越界,却忽略“过小”非法值。负数 skip 或 <code>size 不会 panic,但会导致意外行为:
-
skip = -1→s[-1:2]直接 panic(负索引永远非法) -
size = -5→end = skip + (-5)可能为负,s[3:-2]同样 panic - 即使没 panic(如
skip=0, size=-1→end=-1),也会因违反0 规则而崩溃
真正健壮的分页函数应在开头加守卫:if skip ,而不是等运行时才暴露问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











