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 T
s? So it surely could implement Copy
?
A String is a type that does not implement the Copy trait.
Option<&mut T> is not copyable or clonable, because if it was, it'd allow a user to create more than one mutable borrow to the same data. This breaks rusts current borrowing axioms.
To easily implement the Clone trait, you can also use #[derive(Clone)] . Example: #[derive(Clone)] // we add the Clone trait to Morpheus struct struct Morpheus { blue_pill: f32, red_pill: i64, } fn main() { let f = Morpheus { blue_pill: 0.0, red_pill: 0 }; let copy = f. clone(); // and now we can clone it! }
You can just use . clone() for your duplicate function.
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With