Compactar vetores do mesmo tipo resulta em tipos diferentes no fechamento do mapa

Aug 16 2020

fundo

Dado um tipo de variante enum (não copiável):

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

Tentar executar uma operação em dois desses vetores:

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

Dentro do fechamento, os lhselementos assumem o tipo, l: &AstNodeenquanto os rhselementos compactados assumem o tipo l: AstNode. (Observe as diferentes declarações na tupla de fechamento).

Questões

Por que isso acontece?

Existe uma maneira de iterar elementos de um vetor por valor em vez de por referência? Parece que isso é possível a partir do comportamento observado dos elementos compactados.

(Neste exemplo, esta diferença resulta em uma pequena estranheza na declaração de sintaxe, mas na prática, eu bati contra o verificador de empréstimo ao passar a variável de referência para uma função)

Isenção de responsabilidade: Sou bastante novo no Rust

Respostas

6 kmdreko Aug 16 2020 at 04:55

O Iterator::zipmétodo não está fazendo nada de especial, está simplesmente combinando os dois iteradores. Você está descobrindo que lhs.iter()rende um Iterator<&AstNode>tempo rhsrende um Iterator<AstNode>( &vs não- &).

Existe uma maneira de iterar elementos de um vetor por valor em vez de por referência? Parece que isso é possível a partir do comportamento observado dos elementos compactados.

Sim, existe uma maneira de controlar esse comportamento. A chave é perceber que zip()o argumento de rhsdeve implementar o IntoIteratortraço. Internamente, zip()chamará rhs.into_iter()para obter um iterador dele. O comportamento convencional é que .iter()apenas empresta a fonte e, portanto, só pode fornecer referências aos seus valores. Enquanto consome ou "toma posse" da fonte e pode gerar valores próprios..into_iter()

Combinando isso, você pode fazer lhs.into_iter().zip(rhs)para obter um iterador sobre os valores (AstNode, AstNode)ou usar lhs.iter().zip(rhs.iter())para obter um iterador sobre as referências (&AstNode, &AstNode).