La compressione di vettori dello stesso tipo produce tipi diversi all'interno della chiusura della mappa

Aug 16 2020

sfondo

Dato un tipo di variante enum (non copiabile):

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

Tentativo di eseguire un'operazione su due di questi vettori:

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

All'interno della chiusura, gli lhselementi assumono tipo l: &AstNodementre gli rhselementi zippati assumono tipo l: AstNode. (Notare le diverse dichiarazioni nella tupla di chiusura).

Domande

Perché è così?

Esiste un modo per iterare gli elementi di un vettore per valore invece che per riferimento? Sembrerebbe che ciò sia possibile dal comportamento osservato degli elementi zippati.

(In questo esempio, questa differenza si traduce in una leggera stranezza nella dichiarazione della sintassi, ma in pratica, mi sono imbattuto nel controllo del prestito quando ho passato la variabile di riferimento in una funzione)

Dichiarazione di non responsabilità: sono abbastanza nuovo su Rust

Risposte

6 kmdreko Aug 16 2020 at 04:55

Il Iterator::zipmetodo non sta facendo nulla di speciale, sta semplicemente combinando entrambi gli iteratori. Stai scoprendo che lhs.iter()produce un Iterator<&AstNode>mentre rhsproduce un Iterator<AstNode>( &vs non- &).

Esiste un modo per iterare gli elementi di un vettore per valore invece che per riferimento? Sembrerebbe che ciò sia possibile dal comportamento osservato degli elementi zippati.

Sì, c'è un modo per controllare questo comportamento. La chiave è notare che zip()l'argomento di rhsdeve implementare il IntoIteratortratto. Interamente, zip()chiamerà rhs.into_iter()per ottenere un iteratore da esso. Il comportamento convenzionale è che prende in prestito.iter() solo la fonte e quindi può fornire solo riferimenti ai suoi valori. Mentre consuma o "assume la proprietà" della fonte e può produrre valori di proprietà..into_iter()

Combinando questi, puoi lhs.into_iter().zip(rhs)ottenere un iteratore sui valori (AstNode, AstNode)o utilizzare lhs.iter().zip(rhs.iter())per ottenere un iteratore sui riferimenti (&AstNode, &AstNode).