2015-05-21 9 views
5

próbuję wydrukować drzewa (jest to LinkedList teraz, ale że zostanie ustalona):nie można przenieść z pożyczonym zawartości podczas dopasowywania 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); 
} 

Kompilator mówi:

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

Czytam tylko wartość, nie zmieniając niczego. Przypisuję wartość z odwołania do innej wartości, próbując usunąć wartość Rc<T> i zapisać ją w lokalnej zmiennej mut.

może coś takiego może działać:

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

czy może

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

ale pojawia się ten sam błąd plusa 'next' does not live long enough

Odpowiedz

7

Nie ma potrzeby, aby sklonować tutaj, jest to absolutnie możliwe, aby robić to, co chcesz osiągnąć z referencjami:

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, 
     } 
    } 
} 

Jedyne istotne zmiany z kodu jest, że wzór w meczu jest ref next i current jest typu &Node.

ref Wzory wiążą zmienne przez odwołanie, tj. next ma typ &Rc<Node>. Aby uzyskać od niego numer &Node, musisz usunąć go dwa razy, aby uzyskać Node, a następnie ponownie odwołać się, aby uzyskać &Node. Ze względu na koercje Derefa możliwe jest również napisanie current = &next, a kompilator automatycznie włączy odpowiednią liczbę *.

Zmieniłem również z while (true) na loop, ponieważ jest bardziej idiomatyczne i pomaga kompilatorowi w zrozumieniu kodu.

Wszystkie przejścia struktur przypominających drzewa są wykonywane w ten sposób w Rust. Modele ref nie pozwalają na wyprowadzanie zmiennych, co jest absolutnie konieczne, gdy trzeba tylko odczytać dane. Więcej informacji na temat wzorców i ich interakcji z własnością i pożyczaniem można znaleźć na stronie here.

1

nie mogę dowiedzieć się problem z 1) jeszcze, ale znalazłem odpowiedź na 2).

Na szczycie, trzeba użyć:

use std::rc::Rc;

zamiast

use std::rc;

2

Błąd jest wyświetlany ponieważ domyślnie match wykona ruch.

Po przeniesieniu wartości (tj. Nie została pobrana przez odwołanie lub metoda, która ma wywołanie self) kolejne wywołania nie działają. Prawdopodobnie będziesz musiał sklonować, co jest właściwością zarówno twojego braku struct jak i enum. Po dodaniu tych (#[derive(Clone)) i zmianie current = *next; na current = (*next).clone();, twój program będzie działać ponownie!

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

Jeśli let mut current = &root wtedy można uniknąć clone() jak za odpowiedzi Włodzimierza poniżej (playpen of Vladimir's version).

+0

Więc nie ma sposobu, aby pożyczyć wartość w klauzuli "mecz"? .. –

+0

Oczywiście możesz pożyczyć w klauzuli "mecz", ale w Twoim przypadku jesteś ograniczony przez sposób, w jaki twoja struktura jest tworzona. Nawet jeśli pożyczyłeś, nadal będziesz musiał sklonować go jawnie przez 'Klon' lub niejawnie przez' Kopiuj'. To, czego szukasz, to Iterator, który przemierza drzewo. –

+0

Cóż, może powinienem napisać 'let mut current = Rc :: new (root)', więc myślę, że chcę skopiować tylko Rc i i32, ale nie chcę kopiować całej struktury. Chcę tylko odczytać adres Rc, usunąć go, skopiować i32 i wydrukować, następnie odczytać adres następnego węzła i przypisać bieżący adres do momentu napotkania węzła liści. Jest tylko kopiowanie Rc i i32 (które jest zaimplementowane w standardowej bibliotece, jak również Rc). –

Powiązane problemy