Яка різниця між розміщенням "mut" перед назвою змінної та після ":"?


80

Ось два підписи функцій, які я бачив у документації 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>) { /* ... */ }

Для програмістів на C ++: різниця подібна до покажчика constпроти pointeeconst .
legends2k

Відповіді:


87

mut foo: Tозначає, що у вас є змінна з назвою fooa 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), коли це має сенс.


12
Розумію. Я думаю, це як у C ++, де ви можете мати int const*проти int *constдосягнення різних речей.
Jimmy Lu

3
@Shepmaster Ви можете додати, що mutприв'язка дозволяє мутувати всередині структури (якщо це структура).
Скотт Олсон,

7
@BeyondSora Не думай &mut Typeяк &(mut Type), а як (&mut) Type. Ключове слово mutне використовується в типах загалом, але існує тип посилання &mut.
Скотт Олсон,

2
@BeyondSora Ви можете побачити останню редакцію вищевказаної відповіді. Основне пояснення полягає в тому, коли ви можете мутувати структуру, ви можете мутувати стільки, скільки хочете в структуру (її поля, поля її полів тощо). constПолів немає . Це безпечно, оскільки Rust гарантує, коли ви можете щось мутувати, ніхто інший не зможе прочитати або змінити це одночасно.
Скотт Олсон,

2
@didierc Так. Ви можете думати &Tі &mut Tяк цукор для Ref<T>і RefMut<T>(типи, які я щойно придумав).
Скотт Олсон,

94

Якщо ви походите з 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 використовує підхід "білого списку", де, якщо ви хочете, щоб щось було змінним, ви повинні сказати це явно.


3
Це чудовий стіл. Варто зауважити, що &mut Tпосилання також є аналогічними T* restrictпокажчикам в C: вони не можуть бути псевдонімами. &Tпосилання не мають такого обмеження і не існує типу посилання, аналогічного restrictнекваліфікованим T*покажчикам.
trentcl

1
У мене немає досвіду С, але я все одно вважаю, що це пояснює це краще (з коментарями), на відміну від прийнятої відповіді, іноді краще, ніж довше.
kres0345
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.