40

When looping over a slice of structs, the value I get is a reference (which is fine), however in some cases it's annoying to have to write var as (*var) in many places.

Is there a better way to avoid re-declaring the variable?

fn my_fn(slice: &[MyStruct]) {
    for var in slice {
        let var = *var;  // <-- how to avoid this?

        // Without the line above, errors in comments occur:

        other_fn(var);  // <-- expected struct `MyStruct`, found reference

        if var != var.other {
            // ^^ trait `&MyStruct: std::cmp::PartialEq<MyStruct>>` not satisfied
            foo();
        }
    }
}

See: actual error output (more cryptic).

ideasman42
  • 42,413
  • 44
  • 197
  • 320

2 Answers2

52

You can remove the reference by destructuring in the pattern:

//  |
//  v
for &var in slice {
    other_fn(var);
}

However, this only works for Copy-types! If you have a type that doesn't implement Copy but does implement Clone, you could use the cloned() iterator adapter; see Chris Emerson's answer for more information.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
37

In some cases you can iterate directly on values if you can consume the iterable, e.g. using Vec::into_iter().

With slices, you can use cloned or copied on the iterator:

fn main() {
    let v = vec![1, 2, 3];
    let slice = &v[..];
    for u in slice.iter().cloned() {
        let u: usize = u; // prove it's really usize, not &usize
        println!("{}", u);
    }
}

This relies on the item implementing Clone or Copy, but if it doesn't you probably do want references after all.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Chris Emerson
  • 13,041
  • 3
  • 44
  • 66
  • This is not as memory efficient as Lukas' answer. Additionally, `slice` isn't mutable, so while the iterator might be consumed, `slice` itself won't be so cloning isn't needed. – Eli Sadoff Nov 15 '16 at 15:41
  • 3
    @EliSadoff Actually, both of our solutions will probably result in the same optimized assembly output. Not the complete slice or iterator is cloned, but each element that is yielded. – Lukas Kalbertodt Nov 15 '16 at 15:43
  • @LukasKalbertodt You're right. I also didn't think about the `Clone` vs. `Copy` thing which this accounts for. – Eli Sadoff Nov 15 '16 at 15:44
  • More valuable than the accepted answer because it brings up `into_iter()`. What I really needed was to know the difference from `iter()`: https://stackoverflow.com/questions/34733811/what-is-the-difference-between-iter-and-into-iter – Victor Sergienko May 30 '21 at 18:55
  • @VictorSergienko `iter()` and `into_iter()` on a slice are exactly the same thing: https://github.com/rust-lang/rust/blob/fd9ca0c25ec90f6ed156e6f0e950763ca5171f8a/library/core/src/slice/iter.rs#L23 – CLOVIS Jun 22 '22 at 12:00