Rust
La possession
Recherche…
Introduction
Syntaxe
- Soit x: & T = ... // x est une référence immuable
- Soit x: & mut T = ... // x est une référence exclusive, mutable
- let _ = & mut foo; // emprunter de façon mutuelle (c’est-à-dire exclusivement)
- let _ = & foo; // emprunter immanquablement
- let _ = foo; // déplace foo (nécessite la propriété)
Remarques
- Dans les versions beaucoup plus anciennes de Rust (avant 1.0; mai 2015), une variable possédée avait un type commençant par
~
. Vous pouvez voir cela dans des exemples très anciens.
Propriété et emprunt
Toutes les valeurs dans Rust ont exactement un propriétaire. Le propriétaire est responsable de la suppression de cette valeur lorsqu'il est hors de portée et est le seul à pouvoir transférer la propriété de la valeur. Le propriétaire d'une valeur peut lui donner des références en laissant d'autres parties de code emprunter cette valeur. À tout moment, il peut y avoir un certain nombre de références immuables à une valeur:
let owned = String::from("hello");
// since we own the value, we may let other variables borrow it
let immutable_borrow1 = &owned;
// as all current borrows are immutable, we can allow many of them
let immutable_borrow2 = &owned;
// in fact, if we have an immutable reference, we are also free to
// duplicate that reference, since we maintain the invariant that
// there are only immutable references
let immutable_borrow3 = &*immutable_borrow2;
ou une seule référence mutable ( ERROR
indique une ERROR
compilation):
// for us to borrow a value mutably, it must be mutable
let mut owned = String::from("hello");
// we can borrow owned mutably
let mutable_borrow = &mut owned;
// but note that we cannot borrow owned *again*
let mutable_borrow2 = &mut owned; // ERROR, already borrowed
// nor can we cannot borrow owned immutably
// since a mutable borrow is exclusive.
let immutable_borrow = &owned; // ERROR, already borrowed
S'il existe des références en attente (mutables ou immuables) à une valeur, cette valeur ne peut pas être déplacée (c.-à-d. Que sa propriété est donnée). Nous devrions nous assurer que toutes les références ont été supprimées en premier pour pouvoir déplacer une valeur:
let foo = owned; // ERROR, outstanding references to owned
let owned = String::from("hello");
{
let borrow = &owned;
// ...
} // the scope ends the borrow
let foo = owned; // OK, owned and not borrowed
Emprunts et vies
Toutes les valeurs de Rust ont une durée de vie . La durée de vie d'une valeur couvre le segment de code de la valeur introduit à l'endroit où il est déplacé ou la fin de l'étendue contenant
{
let x = String::from("hello"); // +
// ... :
let y = String::from("hello"); // + |
// ... : :
foo(x) // x is moved | = x's lifetime
// ... :
} // = y's lifetime
Chaque fois que vous empruntez une valeur, la référence résultante a une durée de vie liée à la durée de vie de la valeur empruntée:
{
let x = String::from("hello");
let y = String::from("world");
// when we borrow y here, the lifetime of the reference
// stored in foo is equal to the lifetime of y
// (i.e., between let y = above, to the end of the scope below)
let foo = &y;
// similarly, this reference to x is bound to the lifetime
// of x --- bar cannot, for example, spawn a thread that uses
// the reference beyond where x is moved below.
bar(&x);
}
Appels de propriété et fonction
La plupart des questions relatives à la propriété apparaissent lors de l'écriture de fonctions. Lorsque vous spécifiez les types d'arguments d'une fonction, vous pouvez choisir la manière dont cette valeur est transmise. Si vous avez uniquement besoin d'un accès en lecture seule, vous pouvez prendre une référence immuable:
fn foo(x: &String) {
// foo is only authorized to read x's contents, and to create
// additional immutable references to it if it so desires.
let y = *x; // ERROR, cannot move when not owned
x.push_str("foo"); // ERROR, cannot mutate with immutable reference
println!("{}", x.len()); // reading OK
foo(x); // forwarding reference OK
}
Si foo
besoin de modifier l'argument, il devrait prendre une référence exclusive, mutable:
fn foo(x: &mut String) {
// foo is still not responsible for dropping x before returning,
// nor is it allowed to. however, foo may modify the String.
let x2 = *x; // ERROR, cannot move when not owned
x.push_str("foo"); // mutating OK
drop(*x); // ERROR, cannot drop value when not owned
println!("{}", x.len()); // reading OK
}
Si vous ne spécifiez ni &
ni &mut
, vous dites que la fonction prendra possession d'un argument. Cela signifie que foo
est maintenant aussi responsable de laisser tomber x
.
fn foo(x: String) {
// foo may do whatever it wishes with x, since no-one else has
// access to it. once the function terminates, x will be dropped,
// unless it is moved away when calling another function.
let mut x2 = x; // moving OK
x2.push_str("foo"); // mutating OK
let _ = &mut x2; // mutable borrow OK
let _ = &x2; // immutable borrow OK (note that &mut above is dropped)
println!("{}", x2.len()); // reading OK
drop(x2); // dropping OK
}
Propriété et copie
Certains types de rouille implémentent le trait de Copy
. Les types qui sont Copy
peuvent être déplacés sans posséder la valeur en question. En effet, le contenu de la valeur peut simplement être copié octet par octet dans la mémoire pour produire une nouvelle valeur identique. La plupart des primitives de Rust ( bool
, usize
, f64
, etc.) sont des Copy
.
let x: isize = 42;
let xr = &x;
let y = *xr; // OK, because isize is Copy
// both x and y are owned here
Notamment, Vec
et String
ne sont pas des Copy
:
let x = Vec::new();
let xr = &x;
let y = *xr; // ERROR, cannot move out of borrowed content