我已经在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>`
我希望能够从TraitFoo
方法返回任何可能实现FooHolder::new()
的结构体。在这种情况下,我希望任何T:TraitFoo
作为返回类型而不仅仅是StructBar
。
我尝试过几件事情,但是将new()
移到特质中并不能帮助我,因为实现TraitBar
的新结构可能会将不同的参数带入new()
。
答案 0 :(得分:1)
你似乎几乎走在正确的轨道上。让我们来介绍一下要点:
函数fn new() -> FooHolder<T>
的实现无法选择类型T
。这是由被调用的上下文选择的。所以我们不能强制执行,或者总是假设T = StructBar
。
通常,您可以执行以下两项操作之一:在T
实现的特征中为T
提供构造函数接口。
将
new()
移动到特征中的行为对我没有帮助,因为实现TraitBar的新结构可能会将不同的参数带入new()。
即使您可以这样做,编译器如何知道FooHolder::new()
中期望的参数?这里有可变数量的参数(参见How can I create a function with a variable number of arguments?),因此告诉编译器根据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 }
}
}