"无法移动类型FnOnce"移动盒装功能时

时间:2015-05-23 10:28:47

标签: rust

我试图在Rust中进行一些高阶编程,但是我在处理闭包时遇到了一些困难。这是一个代码片段,说明了我遇到的一个问题:

pub enum Foo {
    Bar(Box<FnOnce(i32)>),
}

pub fn app(i: i32, arg: Foo) {
    match arg {
        Foo::Bar(f) => f(i),
    }
}

当我编译这段代码时,我收到以下错误消息:

error[E0161]: cannot move a value of type std::ops::FnOnce(i32) + 'static: the size of std::ops::FnOnce(i32) + 'static cannot be statically determined
 --> src/main.rs:7:24
  |
7 |         Foo::Bar(f) => f(i),
  |                        ^

由于我将函数放在Box中,我原以为这会解决编译器不知道大小的问题。如何编译上述程序?

2 个答案:

答案 0 :(得分:14)

这是FnOnce特征的定义(简化了一点):

pub trait FnOnce<Args> {
    type Output;

    fn call_once(self, args: Args) -> Self::Output;
}

要调用FnOnce闭包,您需要能够将闭包值本身移动到调用中。请注意,self必须是实际闭包类型; Box<dyn FnOnce>完全是另一种类型。

Rust 1.35

现在可以调用

Box<dyn FnOnce>;您的原始代码按原样运行。

先前版本

标准库中的一种类型,用于解决这种情况:FnBox不幸的是,它不稳定。

您的替代选择是:

  • 重构代码,以便保留实际闭包类型,而不是Box<FnOnce>
  • 请改用Box<FnMut>
  • 等待FnBox稳定。
  • 切换到夜间编译器。

答案 1 :(得分:1)

FnBox不太可能变得稳定,但暂时你可以将F: FnOnce(...) -> ...包裹在Option<F>中,将它绑定在一个可变的闭包中并解开并在里面调用它(所以如果它被多次调用就会引起恐慌);生成的闭包可以装箱为Box<FnMut(...) -> ...>,您可能希望以某种方式包装以确保它仅被使用(&#34;称为&#34;)一次。

见(我的)boxfnonce箱子。