2015-05-21 10 views
5

sto cercando di stampare un albero (si tratta di un LinkedList in questo momento, ma che sarà fisso):Non può uscire di contenuti preso in prestito in caso di corrispondenza un enum

use std::io; 
use std::rc::Rc; 

enum NodeKind { 
    Branch(Rc<Node>), 
    Leaf, 
} 

struct Node { 
    value: i32, 
    kind: NodeKind, 
} 

fn main() { 
    let leaf = Node { value: 10, kind: NodeKind::Leaf }; 
    let branch = Node { value: 50, kind: NodeKind::Branch(Rc::new(leaf)) }; 
    let root = Node { value: 100, kind: NodeKind::Branch(Rc::new(branch)) }; 

    let mut current = root; 
    while true { 
     println!("{}", current.value); 
     match current.kind { 
      NodeKind::Branch(next) => { 
       current = *next; 
      } 
      NodeKind::Leaf => { 
       break; 
      } 
     } 
    } 

    let mut reader = io::stdin(); 
    let buff = &mut String::new(); 
    let read = reader.read_line(buff); 
} 

Il compilatore dice:

error[E0507]: cannot move out of borrowed content 
    --> src/main.rs:24:27 
    | 
24 |     current = *next; 
    |       ^^^^^ cannot move out of borrowed content 

Sto leggendo solo il valore, non sta cambiando nulla. Sto assegnando un valore da un riferimento a un altro valore, provando a dereferenziare un valore Rc<T> e memorizzarlo in una variabile locale mut.

forse qualcosa di simile può funzionare:

while true { 
    println!("{}", current.value); 
    match &current.kind { 
     &NodeKind::Branch(next) => { 
      current = next; 
     } 
     &NodeKind::Leaf => { 
      break; 
     } 
    } 
} 

o forse

let mut current = &Rc::new(root); 
while true { 
    println!("{}", current.value); 
    match current.kind { 
     NodeKind::Branch(next) => { 
      current = &next; 
     } 
     NodeKind::Leaf => { 
      break; 
     } 
    } 
} 

ma ottengo lo stesso errore più 'next' does not live long enough

risposta

7

Non c'è bisogno di clonare qui, è assolutamente possibile fare ciò che si vuole raggiungere con i riferimenti:

use std::rc::Rc; 

enum NodeKind { 
    Branch(Rc<Node>), 
    Leaf, 
} 

struct Node { 
    value: i32, 
    kind: NodeKind, 
} 

fn main() { 
    let leaf = Node { value: 10, kind: NodeKind::Leaf }; 
    let branch = Node { value: 50, kind: NodeKind::Branch(Rc::new(leaf)) }; 
    let root = Node { value: 100, kind: NodeKind::Branch(Rc::new(branch)) }; 

    let mut current = &root; 
    loop { 
     println!("{}", current.value); 
     match current.kind { 
      NodeKind::Branch(ref next) => { 
       current = &**next; 
      } 
      NodeKind::Leaf => break, 
     } 
    } 
} 

Le uniche modifiche importanti dal codice è che il modello nel match è ref next e current è di tipo &Node.

ref i modelli associano le loro variabili per riferimento, ovvero next ha il tipo &Rc<Node>. Per ottenere &Node da esso, è necessario dereferenziarlo due volte per ottenere Node e quindi fare nuovamente riferimento per ottenere &Node. A causa delle coercizioni di Deref, è anche possibile scrivere current = &next e il compilatore inserirà automaticamente un numero appropriato di * s.

ho anche cambiato da while (true) a loop perché è più idiomatica e aiuta il compilatore di ragionare su codice.

Tutti gli attraversamenti di strutture ad albero sono fatti così in Rust. I modelli ref consentono di non spostare le variabili, che è assolutamente necessario quando è necessario leggere solo i dati. Puoi trovare ulteriori informazioni sui modelli e su come interagiscono con la proprietà e il prestito here.

1

io non riesco a capire il problema con 1) ancora, ma ho trovato una risposta per 2).

Nella parte superiore, è necessario utilizzare:

use std::rc::Rc;

invece di

use std::rc;

2

L'errore viene visualizzato perché per impostazione predefinita match eseguirà una mossa.

Dopo un valore viene spostato (cioè non è stato preso come riferimento o metodo che accetta self stato chiamato) chiamate successive sicuro. Probabilmente dovrai clonare, che è una proprietà della tua mancanza struct e enum. Una volta aggiunti quelli (#[derive(Clone)) e modificare current = *next; in current = (*next).clone();, il programma funzionerà di nuovo!

use std::io; 
use std::rc::Rc; 

#[derive(Clone)] 
enum NodeKind { 
    Branch(Rc<Node>), 
    Leaf, 
} 

#[derive(Clone)] 
struct Node { 
    value: i32, 
    kind: NodeKind, 
} 

fn main() { 
    let leaf = Node { value: 10, kind: NodeKind::Leaf }; 
    let branch = Node { value: 50, kind: NodeKind::Branch(std::rc::Rc::new(leaf)) }; 
    let root = Node { value: 100, kind: NodeKind::Branch(std::rc::Rc::new(branch)) }; 

    let mut current = root; 
    while true { 
     println!("{}", current.value); 
     match current.kind { 
      NodeKind::Branch(next) => { 
       current = (*next).clone(); 
      } 
      NodeKind::Leaf => { 
       break; 
      } 
     } 
    } 

    let reader = io::stdin(); 
    let buff = &mut String::new(); 
    let read = reader.read_line(buff); 
} 

Playground

Se let mut current = &root allora si può evitare clone() come per la risposta di Vladimir sotto (playpen of Vladimir's version).

+0

Quindi non c'è modo di prendere in prestito un valore nella clausola 'match'? .. –

+0

Sicuro di poter prendere in prestito una clausola' match', ma nel tuo caso sei limitato dal modo in cui la tua struttura viene creata. Anche se hai preso in prestito, avresti comunque bisogno di clonarlo esplicitamente tramite 'Clone' o implicitamente tramite' Copia'. Quello che sembri cercare è Iterator per attraversare l'albero. –

+0

Beh, forse dovrei scrivere 'let mut current = Rc :: new (root)', quindi idea che voglio copiare solo Rc e i32, ma non voglio copiare un'intera struttura. Voglio solo leggere l'indirizzo Rc, dereferenziarlo, copiare i32 e stamparlo, quindi leggere l'indirizzo del nodo successivo e assegnare la corrente a questo indirizzo fino a quando non viene rilevato il nodo foglia. C'è solo la copia di Rc e i32 (che è implementato in lib standard e Rc). –

Problemi correlati