[英]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
接受不同數量的參數是不現實的。 但是,我們可以通過具有定義構造參數的關聯類型來進行模擬。 在下面的代碼中,我采取了使標識符更加慣用的自由( Struct
或Trait
作為前綴只會引入噪音)。
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.