同じタイプのベクトルを圧縮すると、マップクロージャー内で異なるタイプになります

Aug 16 2020

バックグラウンド

列挙型バリアント型(コピー不可)が与えられた場合:

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

このような2つのベクトルに対して操作を実行しようとしています。

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

クロージャ内で、lhs要素タイプを想定l: &AstNodezip形式一方rhsの要素タイプを取りますl: AstNode。(クロージャータプルの異なる宣言に注意してください)。

質問

なぜそうなのですか?

ベクトルの要素を参照ではなく値で反復する方法はありますか?これは、zip形式の要素の観察された動作から可能であるように思われます。

(この例では、この違いにより構文宣言が少し奇妙になりますが、実際には、参照変数を関数に渡すときにボローチェッカーにぶつかりました)

免責事項:私はRustにかなり慣れていません

回答

6 kmdreko Aug 16 2020 at 04:55

このIterator::zip方法は特別なことは何もしていません。単に両方のイテレータを組み合わせているだけです。しばらくすると(vs non- )になることがlhs.iter()わかります。Iterator<&AstNode>rhsIterator<AstNode>&&

ベクトルの要素を参照ではなく値で反復する方法はありますか?これは、zip形式の要素の観察された動作から可能であるように思われます。

はい、この動作を制御する方法があります。重要なのは、zip()の引数rhsIntoIterator特性を実装する必要があることに注意することです。内部的にzip()rhs.into_iter()、そこからイテレータを取得するために呼び出します。従来の動作ではということである.iter()だけ借りソース従ってのみ、その値への参照を提供することができます。一方で消費または「所有権のかかる」ソースと所有値を得ることができます。.into_iter()

これらを組み合わせて、lhs.into_iter().zip(rhs)値に対してイテレータを取得する(AstNode, AstNode)lhs.iter().zip(rhs.iter())、参照に対してイテレータを取得するために使用できます(&AstNode, &AstNode)