La compression de vecteurs du même type entraîne différents types dans la fermeture de la carte

Aug 16 2020

Contexte

Étant donné un type de variante enum (non copiable):

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

Tentative d'exécuter une opération sur deux de ces vecteurs:

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

Dans la fermeture, les lhséléments prennent le type l: &AstNodetandis que les rhséléments zippés prennent le type l: AstNode. (Notez les différentes déclarations dans le tuple de fermeture).

Des questions

pourquoi est-ce le cas?

Existe-t-il un moyen d'itérer les éléments d'un vecteur par valeur plutôt que par référence? Il semblerait que cela soit possible à partir du comportement observé des éléments zippés.

(Dans cet exemple, cette différence entraîne une légère bizarrerie dans la déclaration de syntaxe, mais en pratique, je me suis heurté au vérificateur d'emprunt lors du passage de la variable de référence dans une fonction)

Avis de non-responsabilité: Je suis assez nouveau sur Rust

Réponses

6 kmdreko Aug 16 2020 at 04:55

La Iterator::zipméthode ne fait rien de spécial, elle combine simplement les deux itérateurs. Vous constatez que cela lhs.iter()donne un Iterator<&AstNode>temps qui rhsdonne un Iterator<AstNode>( &vs non- &).

Existe-t-il un moyen d'itérer les éléments d'un vecteur par valeur plutôt que par référence? Il semblerait que cela soit possible à partir du comportement observé des éléments zippés.

Oui, il existe un moyen de contrôler ce comportement. La clé est de noter que zip()l'argument de rhsdoit implémenter le IntoIteratortrait. Interally, zip()appellera rhs.into_iter()pour en obtenir un itérateur. Le comportement classique est que .iter()seulement emprunte la source et ne peut donc fournir des références à ses valeurs. Alors qu'il consomme ou «s'approprie» la source et peut produire des valeurs possédées..into_iter()

En les combinant, vous pouvez faire lhs.into_iter().zip(rhs)pour obtenir un itérateur sur des valeurs (AstNode, AstNode)ou utiliser lhs.iter().zip(rhs.iter())pour obtenir un itérateur sur des références (&AstNode, &AstNode).