Recently, I wanted to write a type holding parameters for a 3D projection:
use std::ops::Range;
#[derive(Clone, Copy)]
struct CamProj {
/// Near and far pla
Because Range<T>
is often used as an iterator, and having iterators be Copy
was discovered to be a footgun. One specific example had to do with thinking that an iterator was advanced, when in reality it was a copy that was advanced:
for x in it { // a *copy* of the iterator is used here
// ..
}
match it.next() { // the original iterator is used here
// ..
}
Another example:
fn main() {
let stream = "Hello, world!".chars().cycle();
for _ in 0..10 {
let chunk: String = stream.take(3).collect();
println!("{}", chunk);
}
}
And another that prompted a question: Using the same iterator multiple times in Rust
It was believed that having iterators be explicitly copied via clone
helped prevent these cases
Specifically re-adding Copy
to Range
was proposed and rejected. A potential workaround was suggested:
Range fields are public, you can repack them into a copyable tuple (or equivalent) at the constructor/function boundary
See also: