Would like to check if my understandings are correct:
case 1
fn main() {
let x = 5;
let y = x;
assert_eq!(5, y);
println!("y = {}", y);
}
Q1) {assert_eq!(5, &y)} would fail ("no implementation for {integer} == &{integer}
"). I think y clones the value of 5 in the stack? Because it is primitive?
case 2
fn main() {
let x = 5;
let y = &x;
assert_eq!(5, *y);
println!("y = {}", y);
}
Q2) this is how I infer case 1, as seemingly this is how to force a ref instead of cloning in case of primitives? In this case y contains the address (or stack position) of x?
Q3) if x is a string allocated from heap, as in:
fn main() {
let x = String::from("Five");
let y = &x;
assert_eq!("Five", y);
println!("y = {}", y);
}
{assert_eq!(5, y)} would suffice (vs *y) only because of implicit deref of compiler?
case 3
fn main() {
let x = 5;
let &y = &x;
assert_eq!(5, y);
println!("y = {}", y);
}
Similar to case 1 but not a clone? What is y? A ref to ref x? Compiler says y is an integer (presumably '5'), and this because the compiler will auto resolve daisy-chained refs I believe?
case 4
fn main() {
let x = 5;
let &y = &x;
let &z = &&x;
assert_eq!(5, *z);
println!("y = {}", z);
}
The above works but not with {assert_eq!(5, z)} - this is not the same as daisy-chaining refs?
Q1) {assert_eq!(5, &y)} would fail ("no implementation for {integer} == &{integer}"). I think y clones the value of 5 in the stack? Because it is primitive?
It's because it is Copy
, hence values are, well, copied. Rather than moved.
Q2) this is how I infer case 1, as seemingly this is how to force a ref instead of cloning in case of primitives?
You're still forcing a copy when you dereference y
.
In this case y contains the address (or stack position) of x?
Sure.
Q3) if x is a string allocated from heap, {assert_eq!(5, y)} would suffice (vs *y) only because of implicit deref of compiler?
Well first it'd never work because the types can not match, 5
is never a valid string, or reference to string, or anything even remotely close to a string.
Second, implicit dereference only comes into play when calling methods, although as tadman notes a single *
might go through multiple levels of dereference.
(case 4) Similar to case 1 but not a clone? What is y? A ref to ref x? Compiler says y is an integer (presumably '5'), and this because the compiler will auto resolve daisy-chained refs I believe?
There's no daisy chain. The left hand of let
is a pattern. By design, patterns try to reverse an existing operation using the same syntax.
let &y = ...
is a dereference of the value, as if you'd written let y = *...
(except more limited, it only works with references). Not to be confused with ref
(which is essentially the reverse of *
).
Therefore this does the exact same thing as case 1 in a roundabout way, including the copy. y
is an integer, of the same type as x
.
(case 5) The above works but not with {assert_eq!(5, z)} - this is not the same as daisy-chaining refs?
If you apply the rule above you can see that:
x: i32
y: i32
because let &y = &x;
is a complicated way of writing let y = x;
aka a copyz: &i32
because in the same way let &z = &&x;
is a complicated way of writing let z = &x
, aka a reference to x
Which is why you have to dereference z
for the type to match with 5
.