go 1.22 中 for i := range 10 是语义明确的左闭右开迭代([0,10)),仅支持非负整数,i 类型由右侧值决定,不支持步长、负数或自定义范围。

Go 1.22 确实支持 for i := range 10 这种写法,但它不是“语法糖”,而是语义明确、行为固定的迭代机制——别把它当 Python 的 range() 用,更不能指望它支持负数或步长。
range 整数的合法写法和边界规则
Go 1.22 允许 range 后跟一个整数表达式,但仅限于**无符号整数类型或可无损转换为 uint 的有符号整数**(如 int、int64),且值必须 ≥ 0。
-
for i := range 5→i取值为0, 1, 2, 3, 4(左闭右开区间[0, 5)) -
for range 0→ 循环体一次都不执行(合法,不 panic) -
n := -3; for i := range n→ 编译失败:cannot range over n (type int)(负数被拒绝) -
for i := range uint64(100)→ 合法,i类型推导为uint64
为什么不能写 for i := range 10:2 或 range -5..5
Go 没有引入任何类似 Python 切片语法或 Rust 的 ..= 范围操作符。range N 的语义就是“从 0 开始、递增 1、直到 i ”。它不接受额外参数,也不支持自定义起始/步长/方向。
- 想倒序?只能手动写
for i := 9; i >= 0; i-- - 想步长为 2?得用传统
for i := 0; i - 想从 5 开始到 15?
for i := 5; i ,别硬套 <code>range
强行封装成函数(比如 Range(start, end, step))会失去编译器对 range 的优化(如避免逃逸、内联判断),也违背该特性的设计初衷:**简化固定次数的正向计数循环**。
和旧版“伪造 range”的性能差异很真实
过去有人写 for i := range []int{0,1,2,3,4,5,6,7,8,9} 来模拟,这会产生一个长度为 10 的切片,触发堆分配(除非编译器能完全优化掉)。而 for i := range 10 是零分配、零运行时开销的纯编译期展开逻辑。
- 用
go tool compile -S看汇编,前者有CALL runtime.makeslice,后者没有 - 在 hot loop 中(比如渲染帧、批量处理),这种差异会放大
- 但注意:
range 1e6不会生成百万条指令——它仍是循环,只是控制变量由编译器保证不复用、不逃逸
最容易被忽略的隐含类型问题
i 的类型不是固定 int,而是由右侧整数常量或变量的类型决定:
-
for i := range 10→i是int(未指定类型时,整数常量默认int) -
n := int64(10); for i := range n→i是int64,不是int - 如果后续要传给只接受
int的函数(如make([]byte, i)),可能触发类型错误
尤其在泛型代码里,若函数约束为 constraints.Integer,但调用方用了 int64 常量,i 类型就可能意外偏离预期——这不是 bug,是类型系统在按规则工作。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











