迭代器方法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
最佳答案
您的代码中有两个问题。
首先, 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
好的,所以实现了
FnMut
来引用Fn
的实现。我们手中有一个Fn
特质对象,它实现了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);
}
关于iterator - 如何将盒装封口传递给 `take_while`?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39563998/