簡體   English   中英

如何構造可能實現特征的許多潛在結構中的任何一個?

[英]How do I construct any of potentially many structs that implement a trait?

我在下面的Rust中創建了一個小問題的工作示例:

trait TraitFoo {
    fn foo(&self) -> i32;
}

struct StructBar {
    var: i32,
}

impl TraitFoo for StructBar {
    fn foo(&self) -> i32 {
        self.var
    }
}

impl StructBar {
    fn new() -> StructBar {
        StructBar { var: 5 }
    }
}

struct FooHolder<T: TraitFoo> {
    myfoo: T,
}

impl<T: TraitFoo> FooHolder<T> {
    fn new() -> FooHolder<T> {
        FooHolder { myfoo: StructBar::new() }
    }
}

fn main() {
    let aaa = FooHolder::new();
}

無法使用以下命令進行編譯:

error[E0308]: mismatched types
  --> src/main.rs:27:9
   |
27 |         FooHolder { myfoo: StructBar::new() }
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `StructBar`
   |
   = note: expected type `FooHolder<T>`
              found type `FooHolder<StructBar>`

我希望能夠從FooHolder::new()方法返回實現TraitFoo任何潛在結構。 我希望它可以將任何T:TraitFoo作為返回類型,而不是這種情況下的StructBar

我已經嘗試了幾件事,但是將new()移至特征中對我沒有幫助,因為實現TraitBar新結構可能會將不同的參數引入new()

您似乎步入正軌。 讓我們介紹一下要點:

函數fn new() -> FooHolder<T>實現不能選擇類型T 通過調用它的上下文來選擇。 因此,我們無法強制執行或始終假定T = StructBar

通常情況下,你會做兩件事情之一:提供一個構造函數接口, T通過實施的特點T

像將new()移入特征中那樣對我無濟於事,因為實現TraitBar的新結構可能會將不同的參數引入到new()中。

即使您可以做到這一點,編譯器又如何知道FooHolder::new()什么參數呢? 在這里您無法獲得可變數量的參數(請參閱如何創建具有可變數量的參數的函數? ),因此,告訴編譯器根據T接受不同數量的參數是不現實的。 但是,我們可以通過具有定義構造參數的關聯類型來進行模擬。 在下面的代碼中,我采取了使標識符更加慣用的自由( StructTrait作為前綴只會引入噪音)。

trait Foo {
    type Params; // new type parameter

    fn new(params: Self::Params) -> Self; // new static method

    fn foo(&self) -> i32;
}

我們的Bar定義如下:

struct Bar {
    var: i32,
}

impl Foo for Bar {
    type Params = i32;

    fn foo(&self) -> i32 {
        self.var
    }

    fn new(params: Self::Params) -> Self {
        Bar { var: params }
    }
}

並且我們的FooHolder現在將能夠構造類型T的值:

struct FooHolder<T: Foo> {
    myfoo: T,
}

impl<T: Foo> FooHolder<T> {
    fn new(params: T::Params) -> FooHolder<T> {
        FooHolder { myfoo : T::new(params) }
    }
}

使用FooHolder

let aaa = FooHolder::<Bar>::new(5);

當不需要參數來構造T ,我們可以依靠Default特性:

impl<T: Foo + Default> Default for FooHolder<T> {
    fn default() -> Self {
        FooHolder { myfoo: T::default() }
    }
}

完整的游樂場

否則,如果只想避免創建新的類型參數並公開構造函數方法,則通常將T移到保持器中沒有問題。 實際上,標准庫和常用包裝箱中的許多API都遵循這種方法。

impl<T> FooHolder<T> {
    fn new(foo: T) -> Self {
        FooHolder { myfoo: foo }
    }
}

暫無
暫無

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

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