首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将已装箱的闭包传递给`take_while`?

如何将已装箱的闭包传递给`take_while`?
EN

Stack Overflow用户
提问于 2016-09-19 08:51:59
回答 1查看 303关注 0票数 5

迭代器方法take_while接受闭包作为其参数。

例如:

代码语言:javascript
复制
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参数中。相反,我想返回一个函数的闭包。

我似乎很难让它正常工作。这是我天真的尝试:

代码语言:javascript
复制
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

然而,它导致的错误已经被证明很难理解:

代码语言:javascript
复制
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

EN

回答 1

Stack Overflow用户

发布于 2016-09-19 09:08:28

您的代码中有两个问题。

首先,take_while通过引用函数来传递该值(请注意where P: FnMut(&Self::Item) -> bool中的& ),而您的闭包希望通过值接收该值。

代码语言:javascript
复制
fn clos(a: char) -> Box<Fn(&char) -> bool> {
    Box::new(move |&b| a != b)
}

然后就是Box<Fn(&char) -> bool>没有实现FnMut(&char) -> bool的问题。如果我们查看FnMut的文档,我们将看到标准库提供了以下实现:

代码语言:javascript
复制
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

代码语言:javascript
复制
fn main() {
    let s = "hello!";
    let iter = s.chars();
    let s2 = iter.take_while(&*clos('o')).collect::<String>();
    println!("{}", s2);
}
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39563998

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档