Comprimir vectores del mismo tipo da como resultado diferentes tipos dentro del cierre del mapa
Antecedentes
Dado un tipo de variante de enumeración (no copiable):
enum AstNode {
Op(Func, Box<AstNode>, Box<AstNode>),
Val(f64),
// others...
}
Intentar ejecutar una operación sobre dos de estos vectores:
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 del cierre, los lhs
elementos asumen tipo l: &AstNode
mientras que los rhs
elementos con cremallera toman tipo l: AstNode
. (Tenga en cuenta las diferentes declaraciones en la tupla de cierre).
Preguntas
¿Por qué es este el caso?
¿Hay alguna forma de iterar elementos de un vector por valor en lugar de por referencia? Parece que esto es posible por el comportamiento observado de los elementos comprimidos.
(En este ejemplo, esta diferencia da como resultado una ligera rareza en la declaración de sintaxis, pero en la práctica, me he topado con el verificador de préstamos al pasar la variable de referencia a una función)
Descargo de responsabilidad: soy bastante nuevo en Rust
Respuestas
El Iterator::zipmétodo no hace nada especial, simplemente combina ambos iteradores. Está encontrando que lhs.iter()
produce un Iterator<&AstNode>
tiempo rhs
produce un Iterator<AstNode>
( &
frente a no &
).
¿Hay alguna forma de iterar elementos de un vector por valor en lugar de por referencia? Parece que esto es posible por el comportamiento observado de los elementos comprimidos.
Sí, hay una forma de controlar este comportamiento. La clave es notar que zip()
el argumento rhs
debe implementar el IntoIterator
rasgo. Interalmente, zip()
llamará rhs.into_iter()
para obtener un iterador de él. El comportamiento convencional es que .iter()solo toma prestada la fuente y, por lo tanto, solo puede proporcionar referencias a sus valores. Mientras consume o "se apropia" de la fuente y puede producir valores propios..into_iter()
Combinando esos, puede hacer lhs.into_iter().zip(rhs)
para obtener un iterador sobre valores (AstNode, AstNode)
o usar lhs.iter().zip(rhs.iter())
para obtener un iterador sobre referencias (&AstNode, &AstNode)
.