Comprimir vectores del mismo tipo da como resultado diferentes tipos dentro del cierre del mapa

Aug 16 2020

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 lhselementos asumen tipo l: &AstNodemientras que los rhselementos 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

6 kmdreko Aug 16 2020 at 04:55

El Iterator::zipmétodo no hace nada especial, simplemente combina ambos iteradores. Está encontrando que lhs.iter()produce un Iterator<&AstNode>tiempo rhsproduce 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 rhsdebe implementar el IntoIteratorrasgo. 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).