2015-07-13 11 views
7

Ich versuche, eine generische Liste als Übung zu programmieren - ich weiß, dass es bereits von der Syntax unterstützt wird, ich versuche nur zu sehen, ob ich eine rekursive Datenstruktur codieren kann. Wie sich herausstellt, kann ich nicht. Ich stoße auf eine Wand, wenn ich auf mehr als ein Feld eines eigenen Strukturwerts zugreifen möchte.Wie mehrere Strukturfelder zu binden, ohne Fehler "Use verschobenen Wert" zu erhalten?

Was ich tue, ist im Grunde diese - ich definieren eine Struktur, die eine Liste halten wird: gerade dargestellt wird

struct ListNode<T> { 
    val: T, 
    tail: List<T> 
} 

struct List<T>(Option<Box<ListNode<T>>>); 

Leere Liste von List(None).

Nun möchte ich auf eine Liste anhängen können:

impl<T> List<T> { 
    fn append(self, val: T) -> List<T> { 
     match self { 
      List(None) => List(Some(Box::new(ListNode { val: val, tail: List(None) }))), 
      List(Some(node)) => List(Some(Box::new(ListNode { val: node.val, tail: node.tail.append(val) }))) 
     } 
    } 
} 

Ok, so dass mit einem Fehler fehlschlägt „bewegter Wert verwendet: Knoten“ bei node.tail mit einer Erklärung, dass es bei "node.val" verschoben. Das ist verständlich.

Also suche ich nach Möglichkeiten, mehr als ein Feld einer Struktur zu verwenden, und ich finde dies: Avoiding partially moved values error when consuming a struct with multiple fields

Großen, also werde ich das tun:

List(Some(node)) => { 
    let ListNode { val: nval, tail: ntail } = *node; 
    List(Some(Box::new(ListNode { val: nval, tail: ntail.append(val) }))) 
} 

Nun, nein, Still-Node wird bei der Zuweisung verschoben ("Fehler: Verwendung des verschobenen Wertes 'node'" at "tail: ntail"). Scheinbar funktioniert das nicht mehr wie im Link.

ich auch Refs habe versucht, mit:

List(Some(node)) => { 
    let ListNode { val: ref nval, tail: ref ntail } = *node; 
    List(Some(Box::new(ListNode { val: *nval, tail: (*ntail).append(val) }))) 
} 

Dieses Mal ist die Dekonstruktion geht, sondern die Schaffung des neuen Knotens nicht mit „Fehler: kann nicht aus geliehenen Inhalte bewegen“.

Fehle ich etwas offensichtlich hier? Wenn nicht, was ist der richtige Weg, um auf mehrere Felder einer Struktur zuzugreifen, die nicht als Referenz übergeben werden?

Vielen Dank im Voraus für jede Hilfe!

EDIT: Oh, ich sollte wahrscheinlich hinzufügen, dass ich Rust 1.1 stabil verwende.

Antwort

5

Es gibt einige seltsame Interaktion mit Box geht. Sie müssen eine intermediate let-Anweisung hinzufügen, die die Box auspackt.

List(Some(node)) => { 
    let node = *node; // this moves the value from the heap to the stack 
    let ListNode { val, tail } = node; // now this works as it should 
    List(Some(Box::new(ListNode { val: val, tail: tail.append(value) }))) 
} 

Bitte beachte, dass ich value Ihr Funktionsargument umbenannt, so konnte ich ohne Umbenennung die Destrukturierung in der Kurzform schreiben.

Try it out in the playground.

+0

Vielen Dank! Das funktioniert in der Tat :) Warum würde Box so funktionieren? Gibt es eine vernünftige Erklärung? – ebvalaim

+0

Ich bin mir ziemlich sicher, dass es mit der Tatsache zu tun hat, dass der Unboxing-Deref eine Compiler-Magie ist. –

+1

Hier ist der entsprechende Fehler: https://github.com/rust-lang/rust/issues/16223 –