2016-11-12 10 views
2

を住んでいない:借用は十分な長さ

fn main() { 
    let iter = "abc123".chars().filter(&|&c: &char| c.is_digit(10)); 
    match iter.clone().take(3).count() { 
     3 => println!("{}", iter.collect::<String>()), 
     _ => {} 
    } 
} 

私は次のエラーを取得する:

error: borrowed value does not live long enough 
--> test.rs:2:41 
    | 
2 |  let iter = "abc123".chars().filter(&|c: &char| c.is_digit(10)); 
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here 
    |           | 
    |           temporary value created here 
... 
7 | } 
    | - temporary value needs to live until here 
    | 
    = note: consider using a `let` binding to increase its lifetime 

私はエラーが親切であることを理解します上記の行のクロージャをlet f = &|c: &char| c.is_digit(10);working code)と宣言するように指示しますが、なぜこれが必要なのですか?

閉包に2つの参照 - &|c: &char|が含まれていなければならない理由もわかりません。 "abc123".chars()は単純にcharsのイテレータを作成しませんか?

+0

関連性:http://stackoverflow.com/q/31374051/155423;近くの複製:http://stackoverflow.com/q/28776630/155423、http://stackoverflow.com/q/23969191/155423、[working code](http://play.integer32.com/?gist=feb39ad6c2bd1641dcf463b65d560986&version =安定); TL; DR:おそらく 'by_ref'を使いたいと思うでしょう。 – Shepmaster

+0

@Shepmaster私が尋ねようとしていたのは、エラーメッセージで混乱する前にIteratorをクローンする方法です。ですから、私はどのようにして(これは最善の方法ではないと思いますか)(https://play.rust-lang.org/?gist=a8f4f33423f100f857ffe2ce4f0263a8&version=stable&backtrace=0)どうすればいいですか? – gib

答えて

5

but why exactly is this necessary?

私は本当にエラーメッセージよりもはるかに良い、それを説明するのか分からない:

temporary value only lives until here 
temporary value created here 

をあなたは文の(閉鎖自体を)一時的な値を作成し、参照を取っていますそれに。ステートメントが終了すると、値は破棄されます。問題は、コードが参照をnow-destroyedの値に維持しようとしていることです。コンパイラがこれを許可した場合、その参照を使用するときに、ランダムなデータがアクセスされることを知っている人。

the closure has to contain two references

まあ、それはにはありませありません。 filter(|c| c.is_digit(10))はうまく動作します。型推論により、cは自動的に&charとタイプされます。 &cは、パターンマッチングと値の自動デリファレンスのみを行います。メソッド呼び出しがautomatically dereferenceであるため、これは冗長です。

もっと大きな問題は、コードはあなたが行うことができない閉鎖を含むイテレータのクローンを作成しようとしていることである(1234(良、人々は質問をする前に検索することを拒否))。あなたがこれを回避することを選択した賢い方法は、参照をクロージャーにクローンすることです。これは問題ありません。

この問題は、ステートメントの最後に破棄されたものへの参照に戻ります。


目標は、すべての非数字を無視する最初の3桁の数字をスキップして、数字の残りの部分を収集することです場合は、Iterator::skipを使用することができます。

let iter = "abc123".chars().filter(|c| c.is_digit(10)); 
let together: String = iter.skip(3).collect(); 
println!("{}", together); 

の場合目標は3桁の数字しかない場合は最初の3桁のみを取ることです。その数字がいつも集まっていて、それが終わりかどうかを確認することができます。

let mut iter = "abc123".chars().filter(|c| c.is_digit(10)); 
let together: String = iter.by_ref().take(3).collect(); 

if iter.next().is_none() { 
    println!("{}", together); 
} 

これはIterator::by_refを使用します。 の代わりにイテレータを使用すると、by_refは、それに対する変更可能な参照を作成します。イテレータへの変更可能な参照を実装するので、takecollectを呼び出すとうまく動作します。ただし、これらが実行された場合、iterは有効なままです。

+0

ええ、申し訳ありませんが、私はもともと[this](https://play.rust-lang.org/?gist=080f87f21823940bb52e92bc55a1299c&version=stable&backtrace=0)のようなものを持っていましたが、その後私は '&| c :&char | 'コンパイラを和らげようとしています。これはただ私がMCVEに行くことを試みている、私はこれを行う最良の方法ではないことを知っています。 これは本当に啓発です! – gib

関連する問題