1
votes

I have a trait B that defines a function which returns a reference to an object that implements the trait A.

enum Error { }

trait A { }

trait B {
    fn create_a<'a>() -> Result<&'a impl A, Error>;
}

However, when I try to compile I get the following error

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> src/lib.rs:10:37
   |
10 |     fn create_a<'a>() -> Result<&'a impl A, Error>;
   |                                     ^^^^^^
2
As compiler say, you can't use impl in this context, please describe what you try to do because currently the best to solve your issue is to just propose to not write anycode. Explain what you try to do instead of the solution you try to implement.Stargateur
I bet you need a Result<&'a dyn A, Error> hereaSpex
Your create_a function should propably accept an argument of self, either self, &self or &mut self.hellow

2 Answers

6
votes

fn create_a<'a>() -> Result<&'a impl A, Error>;

There is no way to create a reference that will live as long as arbitrary lifetime without having an object that already has that lifetime and can act as its owner—and you have no object here at all, so this signature makes no sense.

For further argument I will assume you do have a self argument with that lifetime (it probably needs to be mutable too): fn create_a<'a>(&'a mut self) -> Result<&'a impl A, Error>;

(note that since there is only one life-time that all mentioned references have, you can elide it: fn create_a(&mut self) -> Result<&impl A, Error>;)

Now there are two options:

  • You can define the concrete type as member of that trait like

    trait B {
        type ImplA: A;
        fn create_a(&mut self) -> Result<&ImplA, Error>;
    }
    

    This is not object-safe, but it will be statically dispatched.

    You should be able to use the impl type alias when implementing the trait to name the type if desired.

  • If you do want B to be object-safe, use object reference, i.e.

    trait B {
        fn create_a(&mut self) -> Result<&dyn A, Error>;
    }
    

    this way dispatch to the return value is always dynamic, but you do that to allow dynamic dispatch to B::create_a in the first place anyway.

-1
votes

There are multiple ways of returning a trait, all of them rely on some kind of indirection.

  1. You could return Box<A>
  2. You could return Rc<A>/Arc<A>
  3. You could use &dyn A
  4. You could use a type parameter T

The difference between 1, 2, 3 and 4 is static vs dynamic dispatching.