How could know the type of a binding if I use auto type deduction when creating a binding? what if the expression on the right side is a borrow(like let x = &5;
I sense some confusion between binding and assigning:
This can be illustrated in two simple lines:
let mut x = 5; // Binding
x = 10; // Assigning
A binding may appear in multiple places in Rust:
let
statements,if let
/while let
conditions,match
expression,for
expression, on the left side of in
.Whenever there is a binding, Rust's grammar also allows pattern matching:
let
statements and for
expressions, the patterns must be irrefutable,if let
, while let
and match
cases, the patterns may fail to match.Pattern matching means that the type of the variable introduced by the binding differs based on how the binding is made:
let x = &5; // x: &i32
let &y = &5; // y: i32
Assigning always requires using =
, the assignment operator.
When assigning, the former value is overwritten, and drop
is called on it if it implements Drop
.
let mut x = 5;
x = 6;
// Now x == 6, drop was not called because it's a i32.
let mut s = String::from("Hello, World!");
s = String::from("Hello, 神秘德里克!");
// Now s == "Hello, 神秘德里克!", drop was called because it's a String.
The value that is overwritten may be as simple as an integer or float, a more involved struct
or enum
, or a reference.
let mut r = &5;
r = &6;
// Now r points to 6, drop was not called as it's a reference.
Overwriting a reference does not overwrite the value pointed to by the reference, but the reference itself. The original value still lives on, and will be dropped when it's ready.
To overwrite the pointed to value, one needs to use *
, the dereference operator:
let mut x = 5;
let r = &mut x;
*r = 6;
// r still points to x, and now x = 6.
If the type of the dereferenced value requires it, drop
will be called:
let mut s = String::from("Hello, World!");
let r = &mut s;
*r = String::from("Hello, 神秘德里克!");
// r still points to s, and now s = "Hello, 神秘德里克!".
I invite you to use to playground to and toy around, you can start from here:
fn main() {
let mut s = String::from("Hello, World!");
{
let r = &mut s;
*r = String::from("Hello, 神秘德里克!");
}
println!("{}", s);
}
Hopefully, things should be a little clearer now, so let's check your samples.
let x = &5;
x
is a reference to i32 (&i32
). What happens is that the compiler will introduce a temporary in which 5
is stored, and then borrow this temporary.
let mut x: &mut T = T{};
Is impossible. The type of T{}
is T
not &mut T
, so this fails to compile. You could change it to let mut x: &mut T = &mut T{};
.
And your last example is similar.