2016-09-19 2 views
3

イテレータメソッドtake_whileは、引数としてクロージャをとります。例えば`take_while`にボックスクローズを渡すにはどうすればいいですか?

fn main() { 
    let s = "hello!"; 
    let iter = s.chars(); 
    let s2 = iter.take_while(|x| *x != 'o').collect::<String>(); 
    //      ^^^^^^^^^^^^^ 
    //       closure 

    println!("{}", s2); // hell 
} 

playground link

これは、単純な閉鎖のための罰金ですが、私はもっと複雑な述語をしたい場合、私はtake_while引数に直接それを書く必要はありません。むしろ、関数からクロージャを戻したいと思います。

私はこれを動作させるのに問題があるようです。しかし

fn clos(a: char) -> Box<Fn(char) -> bool> { 
    Box::new(move |b| a != b) 
} 

fn main() { 
    // println!("{}", clos('a')('b')); // <-- true 
    //      ^--- Using the closure here is fine 
    let s = "hello!"; 
    let mut iter = s.chars(); 
    let s2 = iter.take_while(clos('o')).collect::<String>(); 
    //       ^--- This causes lots of issues 

    println!("{}", s2); 
} 

playground link

、それを理解することは困難であることが判明した原因となるエラー:

error[E0277]: the trait bound `for<'r> Box<std::ops::Fn(char) -> bool>: std::ops::FnMut<(&'r char,)>` is not satisfied 
    --> <anon>:11:23 
    | 
11 |   let s2 = iter.take_while(clos('o')).collect::<String>(); 
    |      ^^^^^^^^^^ trait `for<'r> Box<std::ops::Fn(char) -> bool>: std::ops::FnMut<(&'r char,)>` not satisfied 

error[E0277]: the trait bound `for<'r> Box<std::ops::Fn(char) -> bool>: std::ops::FnOnce<(&'r char,)>` is not satisfied 
    --> <anon>:11:23 
    | 
11 |   let s2 = iter.take_while(clos('o')).collect::<String>(); 
    |      ^^^^^^^^^^ trait `for<'r> Box<std::ops::Fn(char) -> bool>: std::ops::FnOnce<(&'r char,)>` not satisfied 
    | 
    = help: the following implementations were found: 
    = help: <Box<std::boxed::FnBox<A, Output=R> + 'a> as std::ops::FnOnce<A>> 
    = help: <Box<std::boxed::FnBox<A, Output=R> + Send + 'a> as std::ops::FnOnce<A>> 

error: no method named `collect` found for type `std::iter::TakeWhile<std::str::Chars<'_>, Box<std::ops::Fn(char) -> bool>>` in the current scope 
    --> <anon>:11:47 
    | 
11 |   let s2 = iter.take_while(clos('o')).collect::<String>(); 
    |            ^^^^^^^ 
    | 
    = note: the method `collect` exists but the following trait bounds were not satisfied: `Box<std::ops::Fn(char) -> bool> : std::ops::FnMut<(&char,)>`, `std::iter::TakeWhile<std::str::Chars<'_>, Box<std::ops::Fn(char) -> bool>> : std::iter::Iterator` 

error: aborting due to 3 previous errors 

私はFnBoxの使用を含むいくつかの他のものを、試してみましたが、ここに私の素朴な試みでありますそれはうまくいかなかった。私はクロージャーをそれほど使用していないので、何がうまくいかないのか、それを修正する方法を理解したいと思っています。

Related

答えて

7

あなたのコード内の2つの問題があります。

最初に、take_whileは、ファンクション(&where P: FnMut(&Self::Item) -> boolを参照)に値を渡しますが、クロージャーはそれを値で受け取ることを期待しています。

fn clos(a: char) -> Box<Fn(&char) -> bool> { 
    Box::new(move |&b| a != b) 
} 

その後Box<Fn(&char) -> bool>FnMut(&char) -> boolを実装していないという問題があります。私たちはFnMutのドキュメントを見れば、私たちは、標準ライブラリは、これらの実装を提供していることがわかります:

impl<'a, A, F> FnMut<A> for &'a F where F: Fn<A> + ?Sized 
impl<'a, A, F> FnMut<A> for &'a mut F where F: FnMut<A> + ?Sized 

OKを、そうFnMutFnの実装への参照のために実装されています。私たちの手にはFn traitオブジェクトがあり、それはFnを実装しています。 Box<Fn>&Fnにするだけです。最初に左辺値を生成するボックスを参照解除し、次にこの左辺値を参照して&Fnを生成する必要があります。

fn main() { 
    let s = "hello!"; 
    let iter = s.chars(); 
    let s2 = iter.take_while(&*clos('o')).collect::<String>(); 
    println!("{}", s2); 
} 
+1

これは本当により多くのカバレッジが必要なRustのものの1つです。私は自分自身でこの正確な質問を約10回実行しましたが、ドキュメンテーション/フォーラムを通して少しでも検索することなく解決策を見つけ出すのにはまだ問題があります。 –

+0

@SimonWhitehead私は同意します。私はRustをたくさん学ぶのが好きですが、このようなことは私には分かりません(そして私は解決策を理解できないかもしれません)。私は彼らがRustエラーを非常に助けにすることを本当に難しくしていることを知っていますが、オンラインドキュメントがより良くなる可能性があります。私はすべての若い言語が持っている問題だと思う。 – Liam

関連する問題