在学习Rust的过程中,区间类型是一个有历史、也有深度的类型,其重要性不亚于整型。在开发者首次用到区间时,多数是从类似-5..6这样的写法开始的:它表示左闭右开区间[-5, 6),步进为1,非常适合遍历场景。
core::ops::Range仍然是当前默认区间类型
直到Rust 2024,编译器默认采用的区间类型依旧是core::ops::Range,因此前面那段代码展开后即为该类型。而Range本质上是一个结构体,-5..6不过是编译器识别并支持的语法糖,完整的结构体初始化写法与之等价。

core::ops::Range之所以可以直接被迭代,原因在于该类型自身实现了Iterator特征。这个过程会消费掉区间本身——当以一个常态方式再次遍历时,编译器会给出告警,提示区间变量r已被move、也就是已经被消耗掉了。
若想在消费之后继续使用,只能在消费之前先做一次Clone。
设计遗憾来自哪里:迭代器要可变状态,就不能二次使用
Rust标准库对此给出的解释是:core::ops::Range在设计之初就实现了Iterator,而如今这一决定被普遍视为遗憾甚至错误。

逻辑并不复杂——要让类型自动支持迭代,内部状态必然要可变,那么该变量就无法被反复使用。
Rust 2024的纠正:把迭代能力换成IntoIterator
Rust 2024对此作出调整,认为给区间附加迭代器能力并无必要,转而让区间具备“创建迭代器”的能力,也就是实现IntoIterator特征。出于兼容性方面的考虑,标准库新增了区间类型core::range::Range,并为它赋予Copy、Clone与IntoIterator三种能力。
开发者只需修改use语句,其余代码可以完全保持原样。在需要迭代的位置调用IntoIterator特征提供的.into_iter()方法,由区间类型的变量生成一个全新的迭代器;而原来那个区间变量依然可以正常使用。

这一点非常关键。相较老牌的core::ops::Range,新秀core::range::Range把迭代能力从类型本体中拆了出来,既可以与其他能力组合,也避免了Clone被频繁调用。
IntoIterator才是主流:数组、Vec、HashMap、HashSet的都归它管
更值得一提的是,以下这些类型实现的都是IntoIterator特征,而非Iterator特征:数组类型[T; N]与切片[T];列表alloc::vec::Vec;哈希字典std::collections::HashMap;哈希集合std::collections::HashSet。

这样一对比,作为区间默认类型的core::ops::Range就显得相当另类而且突兀,这也可以被看作是Rust早期设计上留下的一个遗憾。
从版本进度来看,截至Rust 1.98.1,RFC#3550中提出的core::range::Range尚未成为-5..6默认映射的类型,但该类型在Stable的Rust中已可正常使用:它最终在1.96.0版本稳定下来。另一方面,core::range模块把现存的core::ops::Range放进了core::range::legacy::Range下,这部分在Rust 1.98.0已经稳定。这些动作或许都在为Rust 2027的最终切换做铺垫。据Rust官方标准库文档,这一迁移路径与新增模块的稳定性标注均已公开。
实践建议:优先用core::range::Range配.into_iter()
如果目标是清晰地判断到底有没有用到Iterator能力,实际开发中建议尽量选用core::range::Range类型,并通过.into_iter()来引发迭代——用法与其他实现IntoIterator的类型保持一致,能够显著降低记忆成本。

当然,语法糖-5..6将来也始终可用;只是在Rust 2027的某一天,它背后的类型有可能不再是core::ops::Range,而是core::range::Range。
作者还补充了一个记忆小技巧:用竹子来记住区间这一概念,竹节对应两个端点。
小结:core::ops::Range把Iterator直接绑在类型上,导致一次迭代即被移动,这一历史选择被广泛视为遗憾;Rust通过core::range::Range将迭代能力拆分为IntoIterator,该类型已在Rust 1.96.0稳定,旧的core::ops::Range也在Rust 1.98.0被归入legacy子模块。开发者在日常编码中优先选用core::range::Range并配合.into_iter(),既与数组、Vec、HashMap、HashSet的处理方式统一,也为Rust 2027可能到来的默认类型切换提前做好准备。
