如何从具有关联类型的包装特征对象中获取特征对象?
How do I obtain a trait object from a wrapper trait object with an associated type?
我有两个特征 Foo
和 Bar
:
trait Bar {
fn get_name(&self) -> &str;
}
trait Foo {
type B: Bar + ?Sized;
fn get_bar(&self) -> &Self::B;
}
实际上,我会有许多不同类型的 Foo
和 Bar
,但每个 Foo
都有一种 Bar
的相关特征。现在保持简单,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
}
}
在某些地方我可以使用泛型和单态,但在某些地方我需要动态调度,比如这个函数需要一个 dyn Foo
其 Bar
是一个 dyn Bar
:
fn some_func_that_needs_dyn_foo_returning_a_dyn_bar(foo: &dyn Foo<B = dyn Bar>) {
// do stuff
}
因为 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 })
}
不满意 return 生命周期是在包装器的实现中:
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`.
我不想在这里有任何静态数据。我想将此处 &dyn Bar
returned 的生命周期与 DynamicFooWrapper
包装的 foo
的生命周期联系起来,因为 &dyn Bar
将存在于至少只要包裹Foo
。例如,在 Foo
包装器上调用 get_bar()
之后,我什至想销毁 Foo
包装器,只要原始 Foo
项目还活着。这应该是可能的,因为这保证了 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})
}
在某些时候 dyn Bar + 'a
将与某些具体类型 T
匹配。 + 'a
约束告诉编译器,如果 T
包含引用,那么这些引用至少与 'a
一样长。如果你想像 &'a Self::B
.
那样在生命周期 'a
中引用 T
,这是必需的
我有两个特征 Foo
和 Bar
:
trait Bar {
fn get_name(&self) -> &str;
}
trait Foo {
type B: Bar + ?Sized;
fn get_bar(&self) -> &Self::B;
}
实际上,我会有许多不同类型的 Foo
和 Bar
,但每个 Foo
都有一种 Bar
的相关特征。现在保持简单,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
}
}
在某些地方我可以使用泛型和单态,但在某些地方我需要动态调度,比如这个函数需要一个 dyn Foo
其 Bar
是一个 dyn Bar
:
fn some_func_that_needs_dyn_foo_returning_a_dyn_bar(foo: &dyn Foo<B = dyn Bar>) {
// do stuff
}
因为 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 })
}
不满意 return 生命周期是在包装器的实现中:
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`.
我不想在这里有任何静态数据。我想将此处 &dyn Bar
returned 的生命周期与 DynamicFooWrapper
包装的 foo
的生命周期联系起来,因为 &dyn Bar
将存在于至少只要包裹Foo
。例如,在 Foo
包装器上调用 get_bar()
之后,我什至想销毁 Foo
包装器,只要原始 Foo
项目还活着。这应该是可能的,因为这保证了 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})
}
在某些时候 dyn Bar + 'a
将与某些具体类型 T
匹配。 + 'a
约束告诉编译器,如果 T
包含引用,那么这些引用至少与 'a
一样长。如果你想像 &'a Self::B
.
'a
中引用 T
,这是必需的