36

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

1 Answer 1

36

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:

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.