“Box”类型

时间:2018-02-03 15:20:50

标签: rust

Rust playground

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

fn main() {
    let job: Box<FnOnce()> = Box::new(|| {});
    // versions that compile
    // let job = Box::new(|| {});
    // let job: Box<FnBox> = Box::new(|| {});
    job.call_box();
}

job.call_box();无法编译:

  
error[E0599]: no method named `call_box` found for type `std::boxed::Box<std::ops::FnOnce()>` in the current scope
  --> src/main.rs:16:9
   |
16 |     job.call_box();
   |         ^^^^^^^^
   |
   = note: job is a function, perhaps you wish to call it
   = note: the method `call_box` exists but the following trait bounds were not satisfied:
           `std::ops::FnOnce() : FnBox`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `call_box`, perhaps you need to implement it:
           candidate #1: `FnBox`

为什么编译器在这里看不到转换为FnBox

我认为当我使用let job = Box::new(|| {});时会产生Box<closure>类型。编译器设法解析job.call_box()Box<closure> - &gt; Box<FnOnce()> - &gt; Box<FnBox>(因为FnBox是针对FnOnce()实施的,而不是closure。为什么不只是Box<FnOnce()> - &gt; Box<FnBox>工作?

1 个答案:

答案 0 :(得分:3)

FnBox 未针对FnOnce()实施

FnOnce()有两个含义:作为特征,作为一种类型。在Box<FnOnce()>中,它是一种(动态的,未标注的)类型。 Since Rust 1.27, the type can be written more explicitly as dyn FnOnce().对于本答案的其余部分,我将使用dyn以便在我谈论特征和动态类型时明确说明。

dyn FnOnce()是所有FnOnce()个特征对象共享的 unsized 类型。不幸的是,FnOnce唯一的方法是按值self取值,这意味着无法在未归类的类型(unsized types can only be used through pointers)上调用它。

您撰写的impl未对FnBox类型实施dyn FnOnce(),因为generic parameters have an implicit Sized bound。如果我们按照该问题的答案的建议并将+ ?Sized添加到F,编译器会提供更有用的错误消息:

impl<F: FnOnce() + ?Sized> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}
error[E0161]: cannot move a value of type F: the size of F cannot be statically determined
 --> src/main.rs:7:9
  |
7 |         (*self)()
  |         ^^^^^^^

明确指出需要Sized的地方。

所有这一切的结果是 FnOnce()特质对象无用。您必须使用FnBox代替,这应该不是问题,因为实现FnOnce()的每个具体类型也实现FnBox。 (但是,我建议不要使用与the experimental fnbox feature相同的名称,以避免混淆。)

同时阅读: