I'm getting a little confused of the syntax &mut or &, especially where should them be put. At first I thought it's some how act the same as const &T in C++, and the concept borrow is the same as r-value and std::move. But the more I coded, the more confused I got about what &mut T actually is, so I got some questions.
Is &mut T a type Or a property mut attached to type &T?
Is there any difference between v: &mut T or &mut v: T in function parameters?
Yes, function parameters take the form pattern: type. Indeef &mut … is also a pattern. You can dereference mutable references using that pattern. E.g.
let x = 42;
let y = &mut 42;
let &mut z = y;
assert!(x == z);
// here the types are:
// x: i32
// y: &mut i32
// z: i32
For function parameters you’ll realistically never want to use this pattern. But technically
fn foo(&mut x: &mut i32) {
… code using “ x ” …
}
where *r is the dereferencing operator applied to r.
Same answer as for the function arguments. let statements also have the form let pattern: type = … (although unlike for function arguments, the type annotation is optional). Note that “what’s the difference” questions are a bit nonsensical if one of the proposed alternatives triggers a compilation error. Writing
let &mut j : i32 = …
will never work because &mut j is a pattern that always has some type of the form &mut ….
What will work is
let &mut j : &mut i32 = …
and the variable j will have type j: i32 then. This is essentially the example I gave above. Here’s the same example but with added type annotations
let x: i32 = 42;
let y: &mut i32 = &mut 42;
let &mut z: &mut i32 = y;
assert!(x == z);
// here the types are:
// x: i32
// y: &mut i32
// z: i32
Note that there’s also another pattern ref mut some_variable that you could use,
let k : &mut i32 = &mut i;
// the same as
let ref mut k: i32 = i;
e.g.
let mut i = 42;
let ref mut k: i32 = i;
// now the type of k is
// k: &mut i32
*k += 1; // modifies i
assert_eq!(i, 43);
Using ref mut like this is super uncommon afaik, you’ll usually want to write
let k = &mut i;
notably without a type annotation as that’s usually going to be redundant here.
TL;DR – you’ll usually only use &mut T as a type in Rust as well as &mut foo as an expression for creating references. (Even though &mut pattern is also a pattern for dereferencing, but that’s not explicitly used too often.)