[英]How do I obtain a trait object from a wrapper trait object with an associated type?
I have two traits Foo
and Bar
:我有两个特征
Foo
和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
.实际上,我会有许多不同类型的
Foo
和Bar
,但每个Foo
都有一种Bar
类型的相关特征。 Keeping it simple for now, the SimpleFoo
is associated with the SimpleBar
:现在保持简单,
SimpleFoo
与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
:在某些地方我可以使用 generics 和单态,但在某些地方我需要动态调度,比如这个 function 比需要一个
dyn Foo
其Bar
是一个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
:由于
SimpleFoo
实现Foo<B = SimpleBar>
而不是Foo<B = dyn Bar>
我不能直接传递它(我希望编译器或派生或其他东西可以在这里做魔术并使这成为可能),所以我有一个包装器 class它持有对某些特定Foo
的引用,并且可以获得其特定的Bar
并将其变成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.我不想在这里有任何 static 数据。 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
.我想将此处返回的
&dyn Bar
的生命周期与DynamicFooWrapper
包装的foo
的生命周期联系起来,因为&dyn Bar
的生命周期至少与包装的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.例如,在
Foo
包装器上调用get_bar()
之后,我什至想销毁Foo
包装器,只要原始Foo
项目还活着。 It should be possible since that guarantees the lifetime of Bar
- I'm just not sure how to express this all.这应该是可能的,因为这保证了
Bar
的生命周期——我只是不确定如何表达这一切。
TL/DR: You need to use dyn Bar + 'a
instead of plain dyn Bar
: TL/DR:您需要使用
dyn Bar + 'a
而不是普通的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
.在某些时候,
dyn Bar + 'a
将与某个具体类型T
匹配。 The + 'a
constraint tells the compiler that if T
contains references, then these references live at least as long as 'a
. + 'a
约束告诉编译器,如果T
包含引用,那么这些引用至少与'a
一样长。 This is required if you want to take a reference to T
with lifetime 'a
as in &'a Self::B
.如果你想引用
T
的生命周期'a
就像在&'a Self::B
中那样,这是必需的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.