2

I have some working code to sum a Range and then use it again later in a for loop. Is it possible to make the code below work without having to clone the Range?

let range = 0..10;
let sum = range.clone().sum::<i8>();
println!("{}", sum);

for data in range.step_by(2).enumerate() {
   println!("{:?}", data);
}
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
weiz
  • 91
  • 2
  • 6
  • 2
    Can you please explain in your question why you want to avoid cloning the Range? – pretzelhammer Jun 28 '20 at 13:12
  • I'm new with Rust and its feel weird to clone it first. – weiz Jun 28 '20 at 13:21
  • 1
    Note that `clone` is expensive only when the underlying data is large and/or heap-allocated, as is the case when cloning a large vector, which must both allocate and clone each element. But cloning a `Range`, which is basically a couple of stack (or register) allocated integers is "zero cost", meaning it costs the same as just writing the same range twice. In other words, don't be afraid to clone where needed. – user4815162342 Jun 28 '20 at 16:51

2 Answers2

5

Range<T> is an iterator. Rust iterators are usually:

mcarton
  • 27,633
  • 5
  • 85
  • 95
  • I see, on call sum its iterate once and cannot be re-use. thats why need clone there. Thanks for the info – weiz Jun 28 '20 at 13:42
1

Refer to @mcarton's answer for a general explanation, but if you're just learning Rust and experimenting with toy examples then simpler version of your code would be to just declare the Range twice:

fn main() {
    let sum: i32 = (0..10).sum();
    println!("{}", sum);
    
    for data in (0..10).step_by(2).enumerate() {
        println!("{:?}", data);
    }
}

If you were writing a function that accepted the Range as an argument then you would have to clone (or be creative in consolidating both loops):

fn fun(mut range: Range<i32>) {
    let sum: i32 = range.clone().sum();
    println!("{}", sum);
    
    for data in range.step_by(2).enumerate() {
        println!("{:?}", data);
    }
}

Regardless, cloning a Range is not a big deal because it's only two integers:

pub struct Range<Idx> {
    pub start: Idx,
    pub end: Idx,
}

So whether you're cloning a 0..10 or a 0..1000000 they're all the same size and the clone operation will be fast and cheap.

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
  • 1
    "the idiomatic version of your code would be to just declare the `Range` twice" I disagree completely. Repeating magical constants is never a good solution. – mcarton Jun 28 '20 at 13:48
  • 1
    I think OP is just learning Rust by experimenting with toy examples. There's no actual requirement that the ranges have to be the same. I've updated my answer to make these assumptions clear. – pretzelhammer Jun 28 '20 at 14:11