3

The compiler says that e1: &i32 and e2: i32. Having read the docs for slice::Iter and the book chapter on loops, I'm still confused.

More generally, can a particular element in a slice be owned? It seems like in case 2, e2 is owning an element, is it?

fn main() {
    let slice = &[1, 2, 3];
    for e1 in slice.iter() {
        println!("{}", e1); // case 1
    }

    for &e2 in slice.iter() {
        println!("{}", e2); // case 2
    }
}
qweruiop
  • 3,156
  • 6
  • 31
  • 55

1 Answers1

6

When used in a destructuring pattern binding, the ampersand & is used to dereference a value:

let a_number: i32 = 42;
let a_reference_to_a_number: &i32 = &a_number;

let another_reference = a_reference_to_a_number;
let &another_number = a_reference_to_a_number;

let () = another_reference; // expected type `&i32`
let () = another_number;    // expected type `i32`

This applies anywhere a pattern is accepted, such as in a let or if let, as a function argument, the for-loop variable, or a match arm.


While initially confusing to many people, this is actually the language being consistent with how enums and structs are pattern matched and thus removed from the inner variable binding:

let a_value: Option<&i32> = Some(&42);

if let Some(&val) = a_value {
    let () = val; // expected type `i32`
}

Note how val is no longer "wrapped" by the Some, just like it is no longer "wrapped" by the reference.

This behavior of & in patterns is why the ref keyword is needed. The ref keyword is used to unambiguously introduce a reference in a pattern match.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I see. Is the ownership transferred to `e2` (in my example)? – qweruiop Jul 19 '17 at 18:16
  • @qweruiop No more or less than if you had used `*e1` in the first loop. An `i32` implements `Copy`, so it will copy the bits. If it didn't implement `Copy`, you'd get the "cannot move out of borrowed context" error. The default is that you cannot take ownership of the value behind a reference because doing so would leave the referenced item in an unknown state. – Shepmaster Jul 19 '17 at 18:19
  • Okay. I tried with a struct without `Copy`, I did get that borrow error. Is it equivalent to say: If a value has references, then its ownership can't be taken through its refs? – qweruiop Jul 19 '17 at 18:32
  • @qweruiop equivalent to which part? You can *never* transfer ownership through a reference. If you have a reference to something that implements `Copy`, then dereferencing it might go ahead and make that copy. If it implements `Clone`, you could call `clone` on the reference and get something you own. In either case, the original owner of the value that the reference is to still owns the value. – Shepmaster Jul 19 '17 at 18:35
  • To "The default is that [...]". But I think I get it. Thanks. – qweruiop Jul 19 '17 at 18:37