Voici deux signatures de fonction que j'ai vues dans la documentation Rust:
fn modify_foo(mut foo: Box<i32>) { *foo += 1; *foo }
fn modify_foo(foo: &mut i32) { *foo += 1; *foo }
Pourquoi le placement différent de mut
?
Il semble que la première fonction pourrait également être déclarée comme
fn modify_foo(foo: mut Box<i32>) { /* ... */ }
mut foo: T
signifie que vous avez une variable appelée foo
qui est un T
. Vous êtes autorisé à modifier ce que la variable fait référence à:
let mut val1 = 2;
val1 = 3; // OK
let val2 = 2;
val2 = 3; // error: re-assignment of immutable variable
Cela vous permet également de modifier les champs d'une structure que vous possédez:
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
signifie que vous avez une variable qui fait référence à (&
) une valeur et vous êtes autorisé à modifier (mut
) valeur référencée (y compris les champs, s'il s'agit d'une structure):
let val1 = &mut 2;
*val1 = 3; // OK
let val2 = &2;
*val2 = 3; // error: cannot assign to immutable borrowed content
Notez que &mut
n'a de sens qu'avec une référence - foo: mut T
n'est pas une syntaxe valide. Vous pouvez également combiner les deux qualificatifs (let mut a: &mut T
), quand cela a du sens.
Si vous venez de C/C++, il pourrait également être utile de penser à cela essentiellement comme ceci:
// 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
Vous remarquerez que ce sont des inverses les uns des autres. C/C++ adopte une approche de "liste noire", où si vous voulez que quelque chose soit immuable, vous devez le dire explicitement, tandis que Rust adopte une approche de "liste blanche", où si vous voulez que quelque chose soit mutable, vous devez le dire explicitement.