Method call resolution for `Box`ed type

前端 未结 1 1673
时光说笑
时光说笑 2021-01-27 02:11

Rust playground:

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

impl FnBox for F {
    fn call_box(self: Box) {
        (*s         


        
1条回答
  •  深忆病人
    2021-01-27 02:46

    Author's note: Since Rust 1.35, an adapter trait like FnBox is not required to call boxed FnOnce closures; read to the end to see why.

    FnBox isn't implemented for FnOnce().

    FnOnce() has two meanings: as a trait, and as a type. In Box, it's a (dynamic, unsized) type. Since Rust 1.27, the type can be written more explicitly as dyn FnOnce(). For the rest of this answer I will use dyn in order to make clear when I'm talking about the trait and when about the dynamic type.

    The impl you wrote doesn't implement FnBox for the type dyn FnOnce(), because generic parameters have an implicit Sized bound. If we follow the advice of that question's answer and add + ?Sized to F, the compiler does give a slightly more helpful error message:

    impl FnBox for F {
        fn call_box(self: Box) {
            (*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)()
      |         ^^^^^^^
    

    Which does explicitly call out the place where Sizedness is required.

    In versions of Rust before 1.35, there was no way to fix this error; trait objects of FnOnce() were just useless. However, today Box implements FnOnce(), so you can call it like a normal closure, without using *:

    impl FnBox for F {
        fn call_box(self: Box) {
            self()
        }
    }
    

    See also

    • What does "Box" mean in Rust?
    • Rust Trait object conversion (why you can't go from one trait object type to another)

    0 讨论(0)
提交回复
热议问题