Compactar vetores do mesmo tipo resulta em tipos diferentes no fechamento do mapa
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 lhs
elementos assumem o tipo, l: &AstNode
enquanto os rhs
elementos 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
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 rhs
rende 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 rhs
deve implementar o IntoIterator
traç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)
.