Kompresowanie wektorów tego samego typu skutkuje różnymi typami w zamknięciu mapy

Aug 16 2020

tło

Biorąc pod uwagę typ wariantu wyliczenia (nie do skopiowania):

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

Próba uruchomienia operacji na dwóch takich wektorach:

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

W zamknięciu lhselementy przyjmują typ, l: &AstNodea rhselementy zapinane na zamek l: AstNode. (Zwróć uwagę na różne deklaracje w krotce zamknięcia).

pytania

Dlaczego tak się dzieje?

Czy istnieje sposób na iterację elementów wektora według wartości zamiast referencji? Wydawałoby się, że jest to możliwe na podstawie obserwowanego zachowania zapinanych elementów.

(W tym przykładzie ta różnica powoduje niewielką dziwność w deklaracji składni, ale w praktyce trafiłem na narzędzie sprawdzania pożyczki podczas przekazywania zmiennej referencyjnej do funkcji)

Zastrzeżenie: Jestem całkiem nowy w Rust

Odpowiedzi

6 kmdreko Aug 16 2020 at 04:55

Iterator::zipMetoda nie robi nic szczególnego, to jest po prostu połączenie obu iteratory. Odkrywasz, że lhs.iter()daje Iterator<&AstNode>chwilę, rhsdaje Iterator<AstNode>( &vs nie &).

Czy istnieje sposób na iterację elementów wektora według wartości zamiast referencji? Wydawałoby się, że jest to możliwe na podstawie obserwowanego zachowania zapinanych elementów.

Tak, istnieje sposób na kontrolowanie tego zachowania. Kluczem jest zauważenie, że zip()argument ten rhsmusi implementować IntoIteratorcechę. Interally, zip()wywoła, rhs.into_iter()aby uzyskać z niego iterator. Konwencjonalne zachowanie polega na tym, że .iter()tylko pożycza źródło i dlatego może podawać tylko odniesienia do jego wartości. Podczas gdy konsumuje lub „przejmuje na własność” źródło i może przynosić posiadane wartości..into_iter()

Łącząc je, możesz lhs.into_iter().zip(rhs)uzyskać iterator dla wartości (AstNode, AstNode)lub użyć go, lhs.iter().zip(rhs.iter())aby uzyskać iterator dla odwołań (&AstNode, &AstNode).