92. core::range — Range Types You Can Actually Copy
Ever tried to reuse a 0..=10 range and hit “use of moved value”? Rust 1.95 stabilises core::range, a new module of range types that implement Copy.
The old pain
The classic range types in std::ops — Range, RangeInclusive — are iterators themselves. That means iterating them consumes them, and they can’t be Copy:
| |
Every time you want to reuse a range you reach for .clone() or rebuild it. Annoying for something that looks like a pair of integers.
The fix: core::range
Rust 1.95 adds new range types in core::range (re-exported as std::range). They’re plain data — Copy, no iterator state baked in — and you turn them into an iterator on demand with .into_iter():
| |
No .clone(), no rebuild. r is just two numbers behind the scenes, so copying it is free.
Passing ranges around
Because the new types are Copy, you can pass them into helpers without worrying about move semantics:
| |
The old std::ops::RangeInclusive would have been moved by the first call.
Field access, not method calls
The new types expose their bounds as public fields — no more .start() / .end() accessors. For RangeInclusive, the upper bound is called last (emphasising that it’s included):
| |
Exclusive Range has start and end in the same way. Either one is simple plain-old-data that you can pattern-match, destructure, or read directly.
When to reach for it
Use core::range whenever you want to store, pass, or reuse a range as a value. The old std::ops ranges are still everywhere (literal syntax, slice indexing, for loops), so there’s no rush to migrate — but for library APIs that take ranges as parameters, the new types are the friendlier choice.
Stabilised in Rust 1.95 (April 2026).