首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Rc<FnMut>作为FnMut

使用Rc<FnMut>作为FnMut
EN

Stack Overflow用户
提问于 2018-01-21 02:55:48
回答 2查看 408关注 0票数 2

给定一个Rc<FnMut>,在迭代器上映射时如何使用它?例如:

代码语言:javascript
复制
use std::rc::Rc;

fn main() {
    let f = Rc::new(|x| x);
    let v = vec![1, 2, 3];
    let _: Vec<_> = v.into_iter().map(f).collect();
}

游乐场

给出误差

代码语言:javascript
复制
error[E0277]: the trait bound `std::rc::Rc<[closure@src/main.rs:6:21: 6:26]>: std::ops::FnMut<({integer},)>` is not satisfied
 --> src/main.rs:8:35
  |
8 |     let _: Vec<_> = v.into_iter().map(f).collect();
  |                                   ^^^ the trait `std::ops::FnMut<({integer},)>` is not implemented for `std::rc::Rc<[closure@src/main.rs:6:21: 6:26]>`

error[E0599]: no method named `collect` found for type `std::iter::Map<std::vec::IntoIter<{integer}>, std::rc::Rc<[closure@src/main.rs:6:21: 6:26]>>` in the current scope
 --> src/main.rs:8:42
  |
8 |     let _: Vec<_> = v.into_iter().map(f).collect();
  |                                          ^^^^^^^
  |
  = note: the method `collect` exists but the following trait bounds were not satisfied:
          `std::iter::Map<std::vec::IntoIter<{integer}>, std::rc::Rc<[closure@src/main.rs:6:21: 6:26]>> : std::iter::Iterator`
          `&mut std::iter::Map<std::vec::IntoIter<{integer}>, std::rc::Rc<[closure@src/main.rs:6:21: 6:26]>> : std::iter::Iterator`

我认为一个简单的*f可以解决这个问题,但是我得到了一个cannot move out of borrowed content错误。

我来得最近的地方是:

代码语言:javascript
复制
use std::rc::Rc;

fn main() {
    let mut f = Rc::new(|x| x);
    let v = vec![1, 2, 3];
    let _: Vec<_> = v.into_iter().map(Rc::get_mut(&mut f).unwrap()).collect();
}

游乐场

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-01-21 03:11:26

直接传递f不起作用,因为Rc<T> where T: FnMut没有实现FnMut

如果闭包没有执行任何变异(即它实现了Fn),则可以编写&*f。这样做是因为:

  1. Rc实现Deref,这将改变*运算符的行为,从而使*x扩展到*(x.deref()),从而使我们能够访问包装好的闭包。
  2. *运算符生成一个lvalue,它允许您引用结果
  3. 对实现Fn 实施 FnMut的类型的不可变引用。
代码语言:javascript
复制
use std::rc::Rc;

fn main() {
    let f = Rc::new(|x| x);
    let v = vec![1, 2, 3];
    let _: Vec<_> = v.into_iter().map(&*f).collect();
}

但是,如果闭包存储在一个&mut *f中,那么Rc就不能工作,因为Rc没有实现DerefMut,因此不允许我们随意借用它的内部。

另一个选项是传递一个将f调用到map的闭包。

代码语言:javascript
复制
use std::rc::Rc;

fn main() {
    let f = Rc::new(|x| x);
    let v = vec![1, 2, 3];
    let _: Vec<_> = v.into_iter().map(|v| f(v)).collect();
}

矫顽力也适用于方法调用。虽然看起来不像,但f(v)实际上扩展到f.call((v,)) (从Rust 1.23开始)(注意这个语法是不稳定的,因此如果启用了fn_traits特性,只有夜间编译器才会接受)。

如果闭包位于Box中,则可以编写&mut *f,因为Box实现了DerefMut

代码语言:javascript
复制
fn main() {
    let mut f = Box::new(|x| x);
    let v = vec![1, 2, 3];
    let _: Vec<_> = v.into_iter().map(&mut *f).collect();
}
票数 4
EN

Stack Overflow用户

发布于 2018-01-21 03:07:56

啊!try_unwrap将允许您移动对闭包的访问,而*f将提供对闭包的引用。

因此,解决办法可以是:

代码语言:javascript
复制
use std::rc::Rc;

fn main() {
    let f = Rc::new(|x| x);
    let v = vec![1, 2, 3];
    match Rc::try_unwrap(f) {
        Ok(f2) => {
            let _: Vec<_> = v.into_iter().map(f2).collect();
        }
        _ => ()
    }
}

(虽然可能有一种更干净的方法来做这件事)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48363238

复制
相关文章

相似问题

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