Какая разница между размещением "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;