【问题标题】:the trait `std::ops::Fn<()>` is not implemented for [closure ...] but only with a binding from the outer scope特征 `std::ops::Fn<()>` 没有为 [closure ...] 实现,但仅使用来自外部范围的绑定
【发布时间】:2018-02-09 02:04:38
【问题描述】:
fn main() {

    let s = Some("xyz".to_string());  //compiler error

    let foo = Box::new(|| s) as Box<Fn() -> Option<String>>;  //ok

    let bar = Box::new(|| Some("xyz".to_string())) as Box<Fn() -> Option<String>>;

    println!("{:?}", foo());
    println!("{:?}", bar());
}

给出错误

error[E0277]: the trait bound `[closure@src/main.rs:5:24: 5:28 s:std::option::Option<std::string::String>]: std::ops::Fn<()>` is not satisfied
 --> src/main.rs:5:15
  |
5 |     let foo = Box::new(|| s) as Box<Fn() -> Option<String>>;
  |               ^^^^^^^^^^^^^^ the trait `std::ops::Fn<()>` is not implemented for `[closure@src/main.rs:5:24: 5:28 s:std::option::Option<std::string::String>]`
  |
  = note: required for the cast to the object type `std::ops::Fn() -> std::option::Option<std::string::String>`

error: aborting due to previous error

Trait std::ops::Fn 状态的文档:

Fn 由闭包自动实现,这些闭包只对捕获的变量进行不可变引用或根本不捕获任何东西,

s 不是可变的,但它不是参考,我正在移动它。

如果我调用s.clone(),编译器错误就会消失,但在我的实际情况下,我想避免这种情况。

如果我使用 FnMut FnOnce 会出现同样的错误,即使它是盒装的,也会抱怨不知道大小。

有没有办法让我可以使用移动的数据?

playground

【问题讨论】:

    标签: rust


    【解决方案1】:

    如果允许,第二次调用闭包会发生什么?请记住,第一次调用闭包时,它会移动s,因此s 现在没有有效值。

    有几种方法可以完成这项工作,具体取决于您的具体需求。

    1. 让闭包返回一个对字符串的引用。

      注意: 我们需要在as 转换表达式的右侧显式写出'a,否则编译器会报错。我认为如果不引入中间函数(make_foo 此处),我们就无法编写正确的生命周期。

      fn make_foo<'a>(s: &'a Option<String>) -> Box<Fn() -> Option<&'a str> + 'a> {
          Box::new(move || s.as_ref().map(|s| &**s)) as Box<Fn() -> Option<&'a str> + 'a>
      }
      
      fn main() {
          let s = Some("xyz".to_string());
          let foo = make_foo(&s);
      
          println!("{:?}", foo());
      }
      
    2. 使用 FnOnce FnBox 而不是 FnFnOnce 闭包可以移动,但最多可以调用一次。由于从 Rust 1.23.0 开始我们不能调用 Box&lt;FnOnce()&gt;,我们需要使用 Box&lt;FnBox()&gt;

      #![feature(fnbox)]
      
      use std::boxed::FnBox;
      
      fn main() {
          let s = Some("xyz".to_string());
          let foo = Box::new(|| s) as Box<FnBox() -> Option<String>>;
      
          println!("{:?}", foo());
      }
      

    但是,由于FnBox 不稳定,您只能将它与夜间编译器一起使用。如果你想支持稳定的编译器,你可以改用boxfnonce crate中定义的BoxFnOnce类型(虽然你需要显式调用闭包为x.call()x()不起作用)。

    【讨论】:

      猜你喜欢
      • 2017-12-05
      • 2020-03-24
      • 2018-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-06
      • 2018-12-29
      • 1970-01-01
      相关资源
      最近更新 更多