2015-05-29 7 views
13

Questo codice non riesce come previsto al let c = a; con errore di compilazione "uso di valore mosso: a":Rilegatura variabile: spostare un & mut o prendere in prestito il referente?

fn main() { 
    let a: &mut i32 = &mut 0; 
    let b = a; 
    let c = a; 
} 

una viene spostato in B e non è più disponibile per un incarico a c. Fin qui tutto bene.

Tuttavia, se ho appena annotare tipo b s' e lasciare tutto il resto da solo:

fn main() { 
    let a: &mut i32 = &mut 0; 
    let b: &mut i32 = a; 
    let c = a; 
} 

il codice non riesce di nuovo a let c = a;

ma questa volta con un messaggio di errore molto diverso: "non può muoversi fuori a perché è preso in prestito ... prendere in prestito dei *a verifica qui: let b: &mut i32 = a; "

Quindi, se ho appena annotare tipo s' b: n o spostare a in b, ma invece un "re" -borrow di *a?

Cosa mi manca?

Cheers.

risposta

7

Quindi, se ho appena annotare tipo s' b: nessuna mossa di a in b, ma invece di un "re" -borrow di *a?

Cosa mi manca?

Assolutamente nulla, come in questo caso queste due operazioni sono semanticamente molto simili (e equivalenti se a e b appartengono alla stessa portata).

  • O si sposta il riferimento a in b, rendendo a un valore mosso, e non è più disponibile.
  • O si rimprovera *a in b, rendendo inutilizzabile a purché b sia in ambito.

Il secondo caso è meno definitivo del primo, è possibile visualizzarlo inserendo la linea che definisce b in un sotto-ambito.

Questo esempio non compilerà perché a viene spostato:

fn main() { 
    let a: &mut i32 = &mut 0; 
    { let b = a; } 
    let c = a; 
} 

Ma questa volontà, perché una volta b esce dallo scope a è sbloccato:

fn main() { 
    let a: &mut i32 = &mut 0; 
    { let b = &mut *a; } 
    let c = a; 
} 

Ora, per la domanda "Perché annotare il tipo di b cambia il comportamento?", la mia ipotesi sarebbe:

  • Quando non è presente un'annotazione del tipo, l'operazione è una mossa semplice e diretta.Nulla è necessario per essere controllato.
  • Quando è presente un'annotazione di tipo, può essere necessaria una conversione (fusione di un &mut _ in un &_ o trasformazione di un riferimento semplice in un riferimento a un oggetto tratto). Quindi il compilatore opta per un nuovo prestito del valore, piuttosto che una mossa.

Ad esempio, questo codice è valido perflectly:

fn main() { 
    let a: &mut i32 = &mut 0; 
    let b: &i32 = a; 
} 

e qui spostano a in b non avrebbe senso, in quanto di tipo diverso. Ancora questo codice compila: b semplicemente prende in prestito *a e il valore non sarà mutevolmente disponibile tramite a finché lo scope b è compreso.

+0

Thx Levans per la risposta. Ho effettivamente controllato la variante subscope in precedenza per verificare che un prestito di "* a" abbia effettivamente avuto luogo. Potrebbe essere stato solo un falso messaggio di compilatore, dopo tutto. Per quanto riguarda la tua ipotesi, mi sentirei molto a disagio se ogni volta che uso un'annotazione di tipo dovrei essere preparato per qualche strana riscrittura del significato ovvio: "let a = b;' dovrebbe sempre essere solo una mossa o una copia, tipo annotato o no. – dacker

+0

@dacker bene, tieni presente che questo comportamento * può * essere raggiunto solo con i riferimenti '& mut', nel qual caso un ri-prestito è semplicemente una copia che rispetta le regole del prestito. – Levans

+0

Ma non era un grande punto in tutti i documenti che ho letto fino ad ora: & muts sono sempre spostati in questi casi? NB: lo stesso comportamento di cui sopra si verifica con assegnazioni di tipo annotated & muts. – dacker

Problemi correlati