How pattern matching in Rust works with `let` statement

Viewed 200

Why does snippet pattern_matching_2 and pattern_matching_3 work whereas pattern_matching_1 doesn't? The compiler suggests that let &x = &foo moves the string hello, which I'm aware of and don't see where the problem is -- I'm not using foo anyway, and compiler doesn't complain anything about pattern_matching_3, which moves the string hello as well.

The example snippets are adapted from this answer, which didn't answer my question.

The code snippets:

fn pattern_matching_1() {
    let foo = String::from("hello");
    let &x = &foo;
    println!("{}", x);
}

fn pattern_matching_2() {
    let foo = 12;
    let &x = &foo;
    println!("{}", x);
}

fn pattern_matching_3() {
    let foo = String::from("hello");
    let x = foo;
    println!("{}", x);
}

The compiler error of pattern_matching_1:

error[E0507]: cannot move out of a shared reference
  --> src/main.rs:26:14
   |
26 |     let &x = &foo;
   |         --   ^^^^
   |         ||
   |         |data moved here
   |         |move occurs because `x` has type `String`, which does not implement the `Copy` trait
   |         help: consider removing the `&`: `x`
2 Answers

he compiler suggests that let &x = &foo moves the string hello, which I'm aware of and don't see where the problem is

The problem is that you've given the compiler an immutable reference to a variable (&foo) and then asked it to move away the underlying data. Which is not an operation that is permitted by immutable references.

To make this more explicit, extract the moving-out part into another function:

fn pattern_matching_1_helper(r: &String) {
    let &x = r;
    println!("{}", x);
}

fn pattern_matching_1() {
    let foo = String::from("hello");
    pattern_matching_1_helper(&foo);
}

I hope it's obvious that pattern_matching_1_helper cannot compile on its own. But the combined version in your code is really no different.

pattern_matching_2 compiles because i32 is Copy, so the compiler doesn't need to move.

fn pattern_matching_3() {
    let foo = String::from("hello");
    let x = foo;
    println!("{}", x);
}

This works because foo is moved into x, so foo is no longer a usable variable. It's ok to move data from the variable that owns it, as long as that variable is never used again.

fn pattern_matching_1() {
    let foo = String::from("hello");
    let &x = &foo;
    println!("{}", x);
}

This doesn't work because foo is still the owner of the string but you are trying to move the data out of x, which has only borrowed it.

pattern_matching_2 works because i32 is Copy, so nothing is moved.

Related