2015-02-01 17 views
10

Sto scrivendo un elenco collegato per descrivere la durata, la proprietà e i riferimenti di Rust. Ho il seguente codice:Impossibile spostare il contenuto preso in prestito durante il tentativo di trasferire la proprietà

pub struct LinkedList { 
    head: Option<Box<LinkedListNode>>, 
} 

pub struct LinkedListNode { 
    next: Option<Box<LinkedListNode>>, 
} 

impl LinkedList { 
    pub fn new() -> LinkedList { 
     LinkedList { head: None } 
    } 

    pub fn prepend_value(&mut self) { 
     let mut new_node = LinkedListNode { next: None }; 

     match self.head { 
      Some(ref head) => new_node.next = Some(*head), 
      None => new_node.next = None, 
     }; 

     self.head = Some(Box::new(new_node)); 
    } 
} 

fn main() {} 

Ma sto ottenendo il seguente errore di compilazione:

error[E0507]: cannot move out of borrowed content 
    --> src/main.rs:18:52 
    | 
18 |    Some(ref head) => new_node.next = Some(*head), 
    |             ^^^^^ cannot move out of borrowed content 

Sto pensando che il nodo head deve attualmente essere di proprietà di self, che è la lista collegata. Quando lo assegno a new_node.next, probabilmente si verificherà un cambio di proprietà.

Preferirei non clonare il valore se possibile in quanto ciò sembra uno spreco. Non voglio solo "prenderlo in prestito" per la durata della funzione. Voglio davvero trasferirne la proprietà.

Come faccio?

Ho già visto error: cannot move out of borrowed content on &mut self e Cannot move out of borrowed content.

Ho provato a rimuovere il braccio di corrispondenza come suggerito nella risposta accettata in una di quelle domande e definendo next nella creazione del nuovo LinkedListNode, ma ottengo lo stesso messaggio di errore.

Ho aggiunto con successo un metodo append che prende uno LinkedListNode da aggiungere alla fine dell'elenco.

+0

possibile duplicato di [\ 'non può uscire di dereference di \' & mut \ '-pointer \' mentre la costruzione di una lista collegata ordinato] (http : //stackoverflow.com/questions/27750985/cannot-move-out-of-dereference-of-mut-pointer-while-building-a-sortedference-linke) – Shepmaster

risposta

19

Cannot move out of borrowed content when trying to transfer ownership

Ad un livello superiore, questo è contro il grano per Rust. Non puoi trasferire la proprietà di qualcosa preso in prestito perché non lo possiedi. Non dovresti prendere in prestito (&Foo) la mia auto e poi darla alla prima persona che vedi per strada! Questo è ancora vero anche se ti presti la mia macchina e ti permetto di apportare modifiche (&mut Foo).

Non è possibile spostare head da un &mut self e in un nuovo nodo perché questo avrebbe lasciato la LinkedList struct in uno stato incoerente - uno dei campi avrebbe un valore indefinito. Questa è una misura fondamentale delle garanzie di sicurezza di Rust.

In questo caso, è possibile utilizzare Option::take. Questo lascerà la variabile dov'è, cambiandola sul posto a None e restituendo il valore precedente. È quindi possibile utilizzare tale valore per costruire il nuovo capo della lista:

pub fn prepend_value(&mut self) { 
    let head = self.head.take(); 
    self.head = Some(Box::new(LinkedListNode { next: head })); 
} 

Una soluzione più generica è quella di assumere la proprietà della struct, invece di prendere in prestito esso. Questo ti permette di fare tutto ciò che vuoi. Si noti che prendiamo self per valore, non con riferimento:

pub fn prepend_value(mut self) -> LinkedList { 
    self.head = Some(Box::new(LinkedListNode { next: self.head })); 
    self 
} 
+0

Quale delle due soluzioni diresti è un codice più idiomatico ? – Gilles

+1

Dato che hai un 'Node' e un' Elenco 'wrapper, probabilmente utilizzerei la versione con' take'; Penso che le persone comprendano '& mut self 'più di' self'. Se la lista fosse composta solo da 'Node's, dovresti usare la versione' self'.Probabilmente lo annoterò come '# [must_use]' per aiutare gli utenti. – Shepmaster

Problemi correlati