Какая разница между размещением "mut" перед именем переменной и после ":"?

Вот две подписи функций, которые я видел в документации Rust:

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

Почему разное размещение mut?

Кажется, что первая функция также может быть объявлена ​​как

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

4 ответа

Решение

mut foo: T означает, что у вас есть переменная с именем foo это T, Вам разрешено изменять то, к чему относится переменная:

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

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

Это также позволяет вам изменять поля структуры, которой вы владеете:

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 означает, что у вас есть переменная, которая ссылается на (&) значение, и вы можете изменить (mut) указанное значение (включая поля, если это структура):

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

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

Обратите внимание, что &mut имеет смысл только со ссылкой - foo: mut T неверный синтаксис Вы также можете объединить два классификатора (let mut a: &mut T), когда это имеет смысл.

Если вы пришли из C/C++, было бы полезно подумать об этом в основном так:

// 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

Вы заметите, что это противоположности друг другу. В C / C++ используется "черный список", где, если вы хотите, чтобы что-то было неизменным, вы должны сказать об этом явно, в то время как Rust использует "белый список", где, если вы хотите, чтобы что-то было изменяемым, вы должны сказать об этом явно.

Следующий перевод на естественный язык, кажется, проясняет мне ситуацию ...

      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}

где

  • {binds mutably} означает, что привязка может относиться к другому экземпляру значения
  • {mutable value} означает, что содержимое значения может измениться
  • Вам нужна изменяемая привязка, чтобы изменить изменяемое значение

Изменяемая переменная ссылочного типа

Когда у тебя есть

      let mut x: &T = value;

Это означает, что это переменная, которая ссылается на экземпляр , как бы сохраняя адрес памяти экземпляра в значении . Эта ссылка (то есть «адрес памяти») является предметом изменения в этом контексте: может быть изменена для ссылки на другой экземпляр, например:

      x = some_other_T_instance;

но референт (т.е. значение экземпляра, на который ссылается) не может быть изменен с помощью:

      // Illegal
*x = a_different_value;

Неизменяемая переменная типа Mutable Reference

Когда у тебя есть

      let x: &mut T = value;

Это означает, что это переменная, которая ссылается на изменяемый экземплярT. В этом случае референт (т.е. фактическое значение) является предметом изменчивости. Его можно изменить с помощью ссылки, подобной этой

      *x = some_other_value;

но сама ссылка (т.е. "адрес памяти" в переменнойx) не могу:

      // illegal
x = a_different_value;
Другие вопросы по тегам