Search code examples
typesrustclosurestype-aliastrait-objects

Calling static method on type alias


While using boxed closures I ran into the following issue:

type Test = Rc<dyn Fn() -> i64>;

fn test_bad() -> Test {
    Test::new(|| 42)
}

fn test_good() -> Test {
    Rc::new(|| 42)
}

In the first case, I'm using the type alias to refer to the new method, whereas I'm using Rc directly in the second case.

In the first case, the compiler complains:

    |       Test::new(|| 42)
    |             ^^^ function or associated item not found in `Rc<(dyn Fn() -> i64 + 'static)>`
    |
    = note: the method `new` exists but the following trait bounds were not satisfied:
            `dyn Fn() -> i64: Sized`

But the second case works just fine. Can somebody please explain the difference? Is there any way to refer to new through the type alias or do I need to wrap it myself?


Solution

  • In test_good, by calling Rc::new on || 42, you don't create an Rc<dyn Fn() -> i64>, but an Rc<ClosureType>, where ClosureType is the unique type of the closure provided, and it is sized. Then, since the Rc<ClosureType> is returned in a function that returns Rc<dyn Fn() -> i64>, it implicitly casts it to a trait object.

    test_bad fails because instead of going from constructing an Rc of a sized closure then casting it to an Rc of an unsized trait object, it tries to directly construct an Rc of an unsized trait object, which fails since all arguments to functions must be sized.

    I don't think there's a direct way to refer to new through the type alias, although you could very easily make your own:

    fn new_test(func: impl 'static + Fn() -> i64) -> Test {
        Rc::new(func)
    }