How does the match expression interpret values vs. references? - reference

In this example, why can I dereference t in the match expression but not on the line directly above?
fn tree_weight_v2(t: &BinaryTree) -> i32 {
// let x = *t; // if uncommented, error: "Cannot move out of borrowed content"
match *t {
BinaryTree::Leaf(payload) => payload,
BinaryTree::Node(ref left, payload, ref right) => {
tree_weight_v2(left) + payload + tree_weight_v2(right)
}
}
}
#[test]
fn tree_demo_2() {
let tree = sample_tree();
assert_eq!(tree_weight_v2(&tree), (1 + 2 + 3) + 4 + 5);
assert_eq!(tree_weight_v2(&tree), (1 + 2 + 3) + 4 + 5);
// no error ^ meaning tree_weight_v2 is not taking ownership of tree
}
enum BinaryTree {
Leaf(i32),
Node(Box<BinaryTree>, i32, Box<BinaryTree>)
}
fn sample_tree() -> BinaryTree {
let l1 = Box::new(BinaryTree::Leaf(1));
let l3 = Box::new(BinaryTree::Leaf(3));
let n2 = Box::new(BinaryTree::Node(l1, 2, l3));
let l5 = Box::new(BinaryTree::Leaf(5));
BinaryTree::Node(n2, 4, l5)
}
playground
I don't believe what the code is doing beyond the match statement to be important - unless of course, that is the source of my confusion.
I'm also curious about how match expressions handle dereferenced values. Specifically, since what the match expression sees is a value of type BinaryTree (without any references), why does the match expression not try to take ownership over it? More generally, how does Rust's match interpret the difference between a dereferenced pointer to a value and a normal value?

let x = *t does not work, because it's moved out of the reference. I.e. this means, with dereferencing t, you get a BinaryTree (without reference). The BinaryTree is borrowed in the function, so assigning it with let x = *t will move the it into the x, which is not possible, since it's borrowed.
The match does work, because match borrows the variable. match *t will not move it out, but it will borrow the BinaryTree. This is a special syntax in Rust and the borrow happens behind the scenes. You can think of this:
fn tree_weight_v2(t: &BinaryTree) -> i32 {
match &*t {
&BinaryTree::Leaf(payload) => payload,
&BinaryTree::Node(ref left, payload, ref right) => {
tree_weight_v2(left) + payload + tree_weight_v2(right)
}
}
}
but all the references are not needed.
See also:
Is there any difference between matching on a reference to a pattern or a dereferenced value?
Should a reference to an enum be dereferenced before it is matched?

Related

Why if let with reference to some yields reference to inner value? [duplicate]

Consider following code
fn main() {
let s = (&&0,);
let (x,) = s; // &&i32
let (&y,) = s; // &i32
let (&&z,) = s; // i32
let t = &(&0,);
let (x,) = t; // &&i32
let (&y,) = t; // i32
let u = &&(0,);
let (x,) = u; // &i32
let (&y,) = u; // mismatched types expected type `{integer}` found reference `&_`
}
Could someone explain, why & pattern behaves differently in every case? I suppose it is tied somehow to match ergonomics, maybe some coercions come into play? But I can't wrap my head around it.
You are correct, this is due to match ergonomics. The first case should hopefully be self explanatory, but the second and third cases can be a bit counter-intuitive.
In the second case:
(x,) is a non-reference pattern (see the second example in the RFC). The t tuple reference is dereferenced, and x is bound as a ref as it also is a non-reference pattern. Note that t.0 was a reference to begin with, thus resulting in x being a double reference.
(&y,) is also a non-reference pattern. The t tuple is dereferenced again to a (&i32,). However, &y is a reference pattern being matched to a &i32 reference. Hence y is bound with move mode and is an i32.
In the third case:
Using the same reasoning as the second case, u is dereferenced via Deref coercion to an (i32,), and x, a non-reference pattern, is bound in ref mode. Hence x is an &i32.
Again with the same reasoning as the second case, u is dereferenced to an (i32,). The &y reference pattern is then matched to an i32, a non-reference, which causes an error.

Why do I not need `ref mut` when pattern matching on a mutable reference? [duplicate]

This question already has answers here:
How does Rust pattern matching determine if the bound variable will be a reference or a value?
(1 answer)
Why does pattern matching on &Option<T> yield something of type Some(&T)?
(1 answer)
Closed 2 years ago.
I'm struggling with destructuring/auto dereferencing.
I have a snippet of code, which works and I kind of see why - a is mutable and we pass a mutable reference to match. In the match statement we have a pattern which expects a mutable reference, and we take inner variables which are references to avoid moving them out.
let x = vec![1, 2];
let y = vec![3, 4];
let mut a = (x, y);
match &mut a {
&mut (ref aa, ref bb) => {}
}
I'm struggling to see why the following pattern works. I expect the pattern not to match to begin with, but it matches and aa and bb are both mutable references (no need for ref mut). I feel that this is some auto dereferencing at play:
match &mut a {
(aa, bb) => {
aa[0] = 2;
}
}
I feel that this is some auto dereferencing at play?
I wouldn't call it "auto" dereferencing because your intention to dereference the matched value is made explicit as part of your destructuring pattern. But yes, when you match a mutable reference against a pattern with a mutable reference it's the same as dereferencing the matched value. You can see this in action in this simpler code example:
fn main() {
for num in &[1, 2, 3] {
// type of `num` inside loop is &i32
// explicit deref required for equality check
if *num == 3 {
println!("found 3");
}
}
// implicit deref in destructuring pattern
for &num in &[1, 2, 3] {
// type of `num` inside loop is i32
// no need for explicit deref operation now
if num == 3 {
println!("found 3");
}
}
}
playground

how to properly distinguish borrow and move? [duplicate]

What is the purpose of & in the code &i in list? If I remove the &, it produces an error in largest = i, since they have mismatched types (where i is &32 and i is i32). But how does &i convert i into i32?
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for &i in list {
if i > largest {
largest = i;
}
}
largest
}
fn main() {
let hey = vec![1, 3, 2, 6, 90, 67, 788, 12, 34, 54, 32];
println!("The largest number is: {}", largest(&hey));
}
Playground
It seems like it is somehow dereferencing, but then why in the below code, is it not working?
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
It says:
4 | hey = &&x;
| ^^^ expected i32, found &&i32
|
= note: expected type `i32`
found type `&&i32`
So normally when you use for i in list, the loop variable i would be of type &i32.
But when instead you use for &i in list, you are not dereferencing anything, but instead you are using pattern matching to explicitly destructure the reference and that will make i just be of type i32.
See the Rust docs about the for-loop loop variable being a pattern and the reference pattern that we are using here. See also the Rust By Example chapter on destructuring pointers.
An other way to solve this, would be to just keep i as it is and then comparing i to a reference to largest, and then dereferencing i before assigning to largest:
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for i in list {
if i > &largest {
largest = *i;
}
}
largest
}
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
This simply doesn't work, because here you are assigning hey, which is an i32, to a reference to a reference to an i32. This is quite unrelated to the pattern matching and destructuring in the loop variable case.
This is the effect of destructuring. I won't completely describe that feature here, but in short:
In many syntax contexts (let bindings, for loops, function arguments, ...) , Rust expects a "pattern". This pattern can be a simple variable name, but it can also contain some "destructuring elements", like &. Rust will then bind a value to this pattern. A simple example would be something like this:
let (a, b) = ('x', true);
On the right hand side there is a value of type (char, bool) (a tuple). This value is bound to the left hand pattern ((a, b)). As there is already a "structure" defined in the pattern (specifically, the tuple), that structure is removed and a und b bind to the tuple's elements. Thus, the type of a is char and the type of b is bool.
This works with a couple of structures, including arrays:
let [x] = [true];
Again, on the right side we have a value of type [bool; 1] (an array) and on the left side we have a pattern in the form of an array. The single array element is bound to x, meaning that the type of x is bool and not [bool; 1]!
And unsurprisingly, this also works for references!
let foo = 0u32;
let r = &foo;
let &c = &foo;
Here, foo has the type u32 and consequently, the expression &foo has the type &u32. The type of r is also &u32, as it is a simple let binding. The type of c is u32 however! That is because the "reference was destructured/removed" by the pattern.
A common misunderstanding is that syntax in patterns has exactly the opposite effect of what the same syntax would have in expressions! If you have a variable a of type [T; 1], then the expression [a] has the type [[T; 1]; 1] → it adds stuff. However, if you bind a to the pattern [c], then y has the type T → it removes stuff.
let a = [true]; // type of `a`: `[bool; 1]`
let b = [a]; // type of `b`: `[[bool; 1]; 1]`
let [c] = a; // type of `c`: `bool`
This also explains your question:
It seems like it is somehow dereferencing, but then why in the below code, it is not working?
fn main() {
let mut hey:i32 = 32;
let x:i32 = 2;
hey = &&x;
}
Because you use & on the expression side, where it adds a layer of references.
So finally about your loop: when iterating over a slice (as you do here), the iterator yields reference to the slice's elements. So in the case for i in list {}, i has the type &i32. But the assignment largest = i; requires a i32 on the right hand side. You can achieve this in two ways: either dereference i via the dereference operator * (i.e. largest = *i;) or destructure the reference in the loop pattern (i.e. for &i in list {}).
Related questions:
Iterating over a slice's values instead of references in Rust?
Why is & needed to destructure a list of tuples during iteration?

What is the purpose of `&` before the loop variable?

What is the purpose of & in the code &i in list? If I remove the &, it produces an error in largest = i, since they have mismatched types (where i is &32 and i is i32). But how does &i convert i into i32?
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for &i in list {
if i > largest {
largest = i;
}
}
largest
}
fn main() {
let hey = vec![1, 3, 2, 6, 90, 67, 788, 12, 34, 54, 32];
println!("The largest number is: {}", largest(&hey));
}
Playground
It seems like it is somehow dereferencing, but then why in the below code, is it not working?
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
It says:
4 | hey = &&x;
| ^^^ expected i32, found &&i32
|
= note: expected type `i32`
found type `&&i32`
So normally when you use for i in list, the loop variable i would be of type &i32.
But when instead you use for &i in list, you are not dereferencing anything, but instead you are using pattern matching to explicitly destructure the reference and that will make i just be of type i32.
See the Rust docs about the for-loop loop variable being a pattern and the reference pattern that we are using here. See also the Rust By Example chapter on destructuring pointers.
An other way to solve this, would be to just keep i as it is and then comparing i to a reference to largest, and then dereferencing i before assigning to largest:
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for i in list {
if i > &largest {
largest = *i;
}
}
largest
}
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
This simply doesn't work, because here you are assigning hey, which is an i32, to a reference to a reference to an i32. This is quite unrelated to the pattern matching and destructuring in the loop variable case.
This is the effect of destructuring. I won't completely describe that feature here, but in short:
In many syntax contexts (let bindings, for loops, function arguments, ...) , Rust expects a "pattern". This pattern can be a simple variable name, but it can also contain some "destructuring elements", like &. Rust will then bind a value to this pattern. A simple example would be something like this:
let (a, b) = ('x', true);
On the right hand side there is a value of type (char, bool) (a tuple). This value is bound to the left hand pattern ((a, b)). As there is already a "structure" defined in the pattern (specifically, the tuple), that structure is removed and a und b bind to the tuple's elements. Thus, the type of a is char and the type of b is bool.
This works with a couple of structures, including arrays:
let [x] = [true];
Again, on the right side we have a value of type [bool; 1] (an array) and on the left side we have a pattern in the form of an array. The single array element is bound to x, meaning that the type of x is bool and not [bool; 1]!
And unsurprisingly, this also works for references!
let foo = 0u32;
let r = &foo;
let &c = &foo;
Here, foo has the type u32 and consequently, the expression &foo has the type &u32. The type of r is also &u32, as it is a simple let binding. The type of c is u32 however! That is because the "reference was destructured/removed" by the pattern.
A common misunderstanding is that syntax in patterns has exactly the opposite effect of what the same syntax would have in expressions! If you have a variable a of type [T; 1], then the expression [a] has the type [[T; 1]; 1] → it adds stuff. However, if you bind a to the pattern [c], then y has the type T → it removes stuff.
let a = [true]; // type of `a`: `[bool; 1]`
let b = [a]; // type of `b`: `[[bool; 1]; 1]`
let [c] = a; // type of `c`: `bool`
This also explains your question:
It seems like it is somehow dereferencing, but then why in the below code, it is not working?
fn main() {
let mut hey:i32 = 32;
let x:i32 = 2;
hey = &&x;
}
Because you use & on the expression side, where it adds a layer of references.
So finally about your loop: when iterating over a slice (as you do here), the iterator yields reference to the slice's elements. So in the case for i in list {}, i has the type &i32. But the assignment largest = i; requires a i32 on the right hand side. You can achieve this in two ways: either dereference i via the dereference operator * (i.e. largest = *i;) or destructure the reference in the loop pattern (i.e. for &i in list {}).
Related questions:
Iterating over a slice's values instead of references in Rust?
Why is & needed to destructure a list of tuples during iteration?

Why does the binary + operator not work with two &mut int?

fn increment(number: &mut int) {
// this fails with: binary operation `+` cannot be applied to type `&mut int`
//let foo = number + number;
let foo = number.add(number);
println!("{}", foo);
}
fn main() {
let mut test = 5;
increment(&mut test);
println!("{}", test);
}
Why does number + number fail but number.add(number) works?
As a bonus question: The above prints out
10
5
Am I right to assume that test is still 5 because the data is copied over to increment? The only way that the original test variable could be mutated by the increment function would be if it was send as Box<int>, right?
number + number fails because they're two references, not two ints. The compiler also tells us why: the + operator isn't implemented for the type &mut int.
You have to dereference with the dereference operator * to get at the int. This would work let sum = *number + *number;
number.add(number); works because the signature of add is fn add(&self, &int) -> int;
Am I right to assume that test is still 5 because the data is copied
over to increment? The only way that the original test variable could
be mutated by the increment function would be if it was send as
Box, right?
Test is not copied over, but is still 5 because it's never actually mutated. You could mutate it in the increment function if you wanted.
PS: to mutate it
fn increment(number: &mut int) {
*number = *number + *number;
println!("{}", number);
}

Resources