rust What's the difference between placing "mut" before a variable name and after the ":"?

ghg1uchk  于 2022-12-13  发布在  其他
关注(0)|答案(4)|浏览(106)

Here are two function signatures I saw in the Rust documentation:

fn modify_foo(mut foo: Box<i32>) { *foo += 1; *foo }
fn modify_foo(foo: &mut i32) { *foo += 1; *foo }

Why the different placement of mut ?
It seems that the first function could also be declared as

fn modify_foo(foo: mut Box<i32>) { /* ... */ }
lymnna71

lymnna711#

If you're coming from C/C++, it might also be helpful to think of it basically like this:

// Rust          C/C++
    a: &T     == const T* const a; // can't mutate either
mut a: &T     == const T* a;       // can't mutate what is pointed to
    a: &mut T == T* const a;       // can't mutate pointer
mut a: &mut T == T* a;             // can mutate both

You'll notice that these are inverses of each other. C/C++ take a "blacklist" approach, where if you want something to be immutable you have to say so explicitly, while Rust takes a "whitelist" approach, where if you want something to be mutable you have to say so explicitly.

mrfwxfqh

mrfwxfqh2#

mut foo: T means you have a variable called foo that is a T . You are allowed to change what the variable refers to:

let mut val1 = 2;
val1 = 3; // OK

let val2 = 2;
val2 = 3; // error: re-assignment of immutable variable

This also lets you modify fields of a struct that you own:

struct Monster { health: u8 }

let mut orc = Monster { health: 93 };
orc.health -= 54;

let goblin = Monster { health: 28 };
goblin.health += 10; // error: cannot assign to immutable field

foo: &mut T means you have a variable that refers to ( & ) a value and you are allowed to change ( mut ) the referred value (including fields, if it is a struct):

let val1 = &mut 2;
*val1 = 3; // OK

let val2 = &2;
*val2 = 3; // error: cannot assign to immutable borrowed content

Note that &mut only makes sense with a reference - foo: mut T is not valid syntax. You can also combine the two qualifiers ( let mut a: &mut T ), when it makes sense.

ars1skjm

ars1skjm3#

The following natural language translation seems to clear things up for me...

let x = value;
  x {binds immutably} to {immutable value}

let mut x = value;
  x {binds mutably} to {possibly mutable value}

let x = &value;
  x {binds immutably} to {a reference to} {immutable value}

let x = &mut value;
  x {binds immutably} to {a reference to} {mutable value}

let mut x = &value;
  x {binds mutably} to {a reference to} {immutable value}

let mut x = &mut value;
  x {binds mutably} to {a reference to} {mutable value}

where

  • {binds mutably} means the binding can be reassigned
  • {mutable value} means the value's contents can change
  • To be able to mutate a value you need both a mutable binding and a mutable value

Note:

  • Reference mutability vs target mutability*

A reference variable such as x , as in let x = &mut y , is a separate variable from the target variable y it is pointing to. In particular, x has its own location on the stack and mutability permissions. As such, if x is immutable, as it is here, then it cannot be reassigned to point to some other variable. That restriction is separate from the ability to mutate the target through it, as in *x = some_value ; the target is a distinct variable with its own mutability permissions. However, if w is mutable, as in let mut w = &mut p , then it can indeed be reassigned to point to some other similarly typed variable: w = &mut z .

jhdbpxl9

jhdbpxl94#

Mutable Variable of Reference Type

When you have

let mut x: &T = value;

This means that x is variable that refers to an instance of T , as if by storing the memory address of the T instance in x 's value. This reference (i.e. the "memory address") is the subject of mutability in this context: x can be modified to refer to a different instance of T like this:

x = some_other_T_instance;

but the referant (i.e. the value of the T instance to which x refers) cannot be changed via x :

// Illegal
*x = a_different_value;

Immutable variable of Mutable Reference type

When you have

let x: &mut T = value;

This means that x is a variable that refers to a mutable instance of T . In this case, the referent (i.e. the actual value) is the subject of mutability. It can be modified through the reference like this

*x = some_other_value;

but the reference itself (i.e. the "memory address" in the variable x ) cannot:

// illegal
x = a_different_value;

相关问题