Reputation: 253
I have two traits Foo
and Bar
:
trait Bar {
fn get_name(&self) -> &str;
}
trait Foo {
type B: Bar + ?Sized;
fn get_bar(&self) -> &Self::B;
}
In reality, I'll have many different types of Foo
s and Bar
s but each Foo
has the associated trait for a type of Bar
. Keeping it simple for now, the SimpleFoo
is associated with the SimpleBar
:
struct SimpleBar {
name: String,
}
impl Bar for SimpleBar {
fn get_name(&self) -> &str {
&self.name
}
}
struct SimpleFoo {
bar: Rc<SimpleBar>,
}
impl Foo for SimpleFoo {
type B = SimpleBar;
fn get_bar(&self) -> &SimpleBar {
&self.bar
}
}
In some places I can use generics and monomorphism, but I need dynamic dispatch in some locations, like this function than needs a dyn Foo
whose Bar
is a dyn Bar
:
fn some_func_that_needs_dyn_foo_returning_a_dyn_bar(foo: &dyn Foo<B = dyn Bar>) {
// do stuff
}
Since SimpleFoo
implements Foo<B = SimpleBar>
not Foo<B = dyn Bar>
I can't directly pass it (I wish the compiler or a derive or something could do magic here and make this possible), so I have a wrapper class which holds a reference to some specific Foo
and can get its specific Bar
and make it into a dyn Bar
:
struct DynamicFooWrapper<'a, F: Foo> {
foo: &'a F,
}
impl<'a, F> Foo for DynamicFooWrapper<'a, F>
where
F: Foo,
<F as Foo>::B: Sized,
{
type B = dyn Bar;
fn get_bar(&self) -> &'a Self::B {
self.foo.get_bar()
}
}
fn main() {
let b = Rc::new(SimpleBar {
name: "Bar101".to_owned(),
});
let f = SimpleFoo { bar: b.clone() };
some_func_that_needs_dyn_foo_returning_a_dyn_bar(&DynamicFooWrapper { foo: &f })
}
It's unhappy about the return lifetimes is in the implementation of the wrapper:
error[E0310]: the associated type `<F as Foo>::B` may not live long enough
--> src/main.rs:45:9
|
45 | self.foo.get_bar()
| ^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<F as Foo>::B: 'static`...
= note: ...so that the type `<F as Foo>::B` will meet its required lifetime bounds
For more information about this error, try `rustc --explain E0310`.
I don't want to have any static data here. I'd like to tie the lifetime of the &dyn Bar
returned here to the lifetime of the foo
which the DynamicFooWrapper
wraps because that &dyn Bar
will live at least as long as the wrapped Foo
. For instance, after calling get_bar()
on the Foo
wrapper, I'd even like to destroy the Foo
wrapper and as long as the original Foo
item is alive. It should be possible since that guarantees the lifetime of Bar
- I'm just not sure how to express this all.
Upvotes: 3
Views: 481
Reputation: 23443
TL/DR: You need to use dyn Bar + 'a
instead of plain dyn Bar
:
fn some_func_that_needs_dyn_foo_returning_a_dyn_bar<'a>(_foo: &dyn Foo<B=dyn Bar + 'a>) {
// do stuff
}
struct DynamicFooWrapper<'a, F: Foo> {
foo: &'a F,
}
impl<'a, F> Foo for DynamicFooWrapper<'a, F>
where
F: Foo,
<F as Foo>::B: Sized,
{
type B = dyn Bar + 'a;
fn get_bar(&self) -> &'a Self::B {
self.foo.get_bar()
}
}
fn main() {
let b = Rc::new(SimpleBar {name: "Bar101".to_owned()});
let f = SimpleFoo { bar: b.clone() };
some_func_that_needs_dyn_foo_returning_a_dyn_bar(&DynamicFooWrapper{foo: &f})
}
At some point the dyn Bar + 'a
will be matched with some concrete type T
. The + 'a
constraint tells the compiler that if T
contains references, then these references live at least as long as 'a
. This is required if you want to take a reference to T
with lifetime 'a
as in &'a Self::B
.
Upvotes: 1