Rust
Proprietà
Ricerca…
introduzione
Sintassi
- let x: & T = ... // x è un riferimento immutabile
- sia x: & mut T = ... // x è un riferimento esclusivo e mutevole
- lasciamo _ = & mut foo; // prendere in prestito in modo mutabile (cioè, esclusivamente)
- lasciamo _ = & foo; // prendo in prestito immutabilmente
- lascia _ = pippo; // move foo (richiede la proprietà)
Osservazioni
- Nelle versioni molto vecchie di Rust (prima di 1.0, maggio 2015), una variabile di proprietà aveva un tipo che inizia con
~
. Si può vedere questo in esempi molto vecchi.
Proprietà e prestito
Tutti i valori in Rust hanno esattamente un proprietario. Il proprietario è responsabile di rilasciare quel valore quando esce dal campo di applicazione ed è l'unico che può spostare la proprietà del valore. Il proprietario di un valore può dare dei riferimenti ad esso lasciando che altri pezzi di codice prendano in prestito quel valore. In qualsiasi momento, potrebbe esserci un numero qualsiasi di riferimenti immutabili a un valore:
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;
o un singolo riferimento mutabile ( ERROR
denota un errore in fase di compilazione):
// 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
Se ci sono riferimenti in sospeso (mutabili o immutabili) a un valore, tale valore non può essere spostato (cioè, la sua proprietà è data via). Dovremmo assicurarci che prima tutti i riferimenti siano stati rilasciati per poter spostare un valore:
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
Prende in prestito e vite
Tutti i valori in Rust hanno una durata . La durata di un valore copre il segmento di codice dal valore introdotto al punto in cui viene spostato o alla fine dell'ambito di contenimento
{
let x = String::from("hello"); // +
// ... :
let y = String::from("hello"); // + |
// ... : :
foo(x) // x is moved | = x's lifetime
// ... :
} // = y's lifetime
Ogni volta che si prende in prestito un valore, il riferimento risultante ha una durata legata alla durata del valore preso in prestito:
{
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);
}
Proprietà e chiamate di funzione
La maggior parte delle domande relative alla proprietà si verificano quando si scrivono le funzioni. Quando si specificano i tipi di argomenti di una funzione, è possibile scegliere in che modo viene passato quel valore. Se è necessario solo l'accesso di sola lettura, è possibile prendere un riferimento immutabile:
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
}
Se foo
bisogno di modificare l'argomento, dovrebbe avere un riferimento esclusivo e mutevole:
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
}
Se non si specifica né &
o &mut
, si sta dicendo che la funzione assumerà la proprietà di un argomento. Ciò significa che foo
è ora anche responsabile della caduta di 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
}
Proprietà e il tratto di copia
Alcuni tipi di ruggine implementano il tratto Copy
. I tipi che sono Copy
possono essere spostati senza possedere il valore in questione. Questo perché il contenuto del valore può essere semplicemente copiato byte per byte in memoria per produrre un nuovo valore identico. La maggior parte dei primitivi in Rust ( bool
, usize
, f64
, ecc.) Sono Copy
.
let x: isize = 42;
let xr = &x;
let y = *xr; // OK, because isize is Copy
// both x and y are owned here
In particolare, Vec
e String
non sono Copy
:
let x = Vec::new();
let xr = &x;
let y = *xr; // ERROR, cannot move out of borrowed content