Function parameter: `v: &mut T or `&mut v: T`

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.

  1. Is &mut T a type Or a property mut attached to type &T?
  2. Is there any difference between v: &mut T or &mut v: T in function parameters?
  3. What's the difference as below:
    let &mut j : i32 = i;
    let k : &mut i32 = &mut i;

It’s a type.

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 ” …
}

is possible and essentially the same as

fn foo(r: &mut i32) {
    … code using “ *r ” …
}

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.)

5 Likes

https://h2co3.github.io/pattern/

1 Like

I'm sorry I use an IDE, and it doesn't report me an error as usual, the some code I pasted indeed cannot compile.

And may I ask what is a "pattern"? pattern: type looks like something in a BNF...

A pattern is something that can appear

match expr {
    HERE => …,
    AND_HERE => …,
}

in a match expression. Unlike match, let statements and function arguments support “irrefutable” patterns only.

For example, this works because (a, b) is a pattern:

let (a, b) = function_that_returns_a_tuple();

Correct if I'm wrong (please ignore the borrow rules):

    let mut x = 42;
    let y = &mut x; // dereference expression
    let z : &mut i32 = y; // type
    let &mut u = y; // pattern

let y = &mut x is taking a reference, not dereferencing. let &mut u = y and let u = *y both dereference.

2 Likes

In case you’re finding tuples more intuitive, it’s basically the same situation there

let x1 = 42;
let x2 = 2.8;
let y = (x1, x2); // tuple expression
let z: (i32, f64) = y; // type
let (u1, u2) = y; // pattern

Thanks guys, I think the root problem is that I'm lacking the knowledge of "pattern".

It's a long chapter, but you can read about it in that link :point_up:

By the way, is there any grammar BNF online? Rust's grammar syntax somehow is too complicate to me...

The grammar is described throughout The Reference. For example, starting here you can click on Item to Function to BlockExpression to Statement to LetStatement to PatternNoTopAlt, the last of which is another resource to learn about patterns.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.