Das Zippen von Vektoren desselben Typs führt zu unterschiedlichen Typen beim Schließen der Karte

Aug 16 2020

Hintergrund

Bei einem Enum-Variantentyp (nicht kopierbar):

enum AstNode {
  Op(Func, Box<AstNode>, Box<AstNode>),
  Val(f64),
  // others...
}

Versuch, eine Operation über zwei solche Vektoren auszuführen:

fn apply_func_iterative(func: Func, lhs: Vec<AstNode>, rhs: Vec<AstNode>) -> Vec<AstNode> {
    lhs.iter().zip(rhs).map(|(&l,r)| apply_func(func,l,r)).collect()  // l and r are declared differently!
}

fn apply_func(func: Func, lhs: AstNode, rhs: AstNode) -> AstNode {
    // magic happens here!
}

Innerhalb des Verschlusses nehmen die lhsElemente den Typ an, l: &AstNodewährend die gezippten rhsElemente den Typ annehmen l: AstNode. (Beachten Sie die unterschiedlichen Deklarationen im Verschlusstupel).

Fragen

Warum ist das so?

Gibt es eine Möglichkeit, Elemente eines Vektors nach Wert anstatt nach Referenz zu iterieren? Es scheint, dass dies aufgrund des beobachteten Verhaltens der gezippten Elemente möglich ist.

(In diesem Beispiel führt dieser Unterschied zu einer leichten Seltsamkeit bei der Syntaxdeklaration, aber in der Praxis bin ich beim Übergeben der Referenzvariablen an eine Funktion auf den Kreditprüfer gestoßen.)

Haftungsausschluss: Ich bin ziemlich neu bei Rust

Antworten

6 kmdreko Aug 16 2020 at 04:55

Die Iterator::zipMethode macht nichts Besonderes, sondern kombiniert einfach beide Iteratoren. Sie stellen fest, dass lhs.iter()eine Iterator<&AstNode>Weile rhseine Iterator<AstNode>( &gegen Nicht- &) ergibt .

Gibt es eine Möglichkeit, Elemente eines Vektors nach Wert anstatt nach Referenz zu iterieren? Es scheint, dass dies aufgrund des beobachteten Verhaltens der gezippten Elemente möglich ist.

Ja, es gibt eine Möglichkeit, dieses Verhalten zu steuern. Der Schlüssel ist zu bemerken, dass zip()das Argument rhsdas IntoIteratorMerkmal implementieren muss . Intern zip()wird aufgerufen rhs.into_iter(), um einen Iterator daraus zu erhalten. Das herkömmliche Verhalten ist , dass .iter()nur leiht sich die Quelle und daher nur Verweise auf seine Werte liefern kann. Während verbraucht oder "übernimmt" die Quelle und kann eigene Werte liefern..into_iter()

Wenn Sie diese kombinieren, können Sie lhs.into_iter().zip(rhs)einen Iterator über Werte abrufen (AstNode, AstNode)oder lhs.iter().zip(rhs.iter())einen Iterator über Referenzen abrufen (&AstNode, &AstNode).