簡體   English   中英

如何從具有關聯類型的包裝特征 object 獲取特征 object?

[英]How do I obtain a trait object from a wrapper trait object with an associated type?

我有兩個特征FooBar

trait Bar {
    fn get_name(&self) -> &str;
}

trait Foo {
    type B: Bar + ?Sized;

    fn get_bar(&self) -> &Self::B;
}

實際上,我會有許多不同類型的FooBar ,但每個Foo都有一種Bar類型的相關特征。 現在保持簡單, SimpleFooSimpleBar相關聯:

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
    }
}

在某些地方我可以使用 generics 和單態,但在某些地方我需要動態調度,比如這個 function 比需要一個dyn FooBar是一個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 })
}

對返回生命周期的不滿在於包裝器的實現:

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`.

我不想在這里有任何 static 數據。 我想將此處返回的&dyn Bar的生命周期與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一樣長。 如果你想引用T的生命周期'a就像在&'a Self::B中那樣,這是必需的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM