问题
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 plane
proj_range: Range<f32>,
/// Field of view
fov: cgmath::Rad<f32>, // `Rad` derives `Copy`
/// Width divided by height
aspect_ratio: f32,
}
However, I got this error:
error[E0204]: the trait `Copy` may not be implemented for this type
--> <anon>:3:21
|
3 | #[derive(Clone, Copy)]
| ^^^^
...
6 | proj_range: Range<f32>,
| ---------------------- this field does not implement `Copy`
So apparently, Range<T> never implements Copy, even if T is Copy, like f32 is. Why is that? I thought a Range<T> would just be a pair of Ts? So it surely could implement Copy?
回答1:
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:
- Why are iterators not copyable?
- Re-using a range for iteration
来源:https://stackoverflow.com/questions/43416914/why-doesnt-opsranget-implement-copy-even-if-t-is-copy