trait Foo {}
trait Bar: Foo {}
struct Zxc;
impl Foo for Zxc {}
struct Baz;
impl Bar for Baz {}
impl Foo for Baz {}
struct Abc<F: Foo> {
f: F
}
impl<F: Foo> Abc<F> {
fn bared<B: Bar>(&mut self, b: B) {
self.f = b;
}
}
fn main() {
let mut abc = Abc { f: Zxc };
abc.bared(Baz);
}
Abc
存储Foo
特征; abc.bared(Baz)
Baz
Foo
实施Bar
和Baz
,但在Abc
中保存<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:baselineAligned="false"
android:orientation="horizontal"
>
<fragment
android:id="@+id/list_Fragment1xml_mainAct_ID"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".08"
class="com.knowledgeflex.lpm_qrt.Menu_Fragment1" >
</fragment>
<fragment
android:id="@+id/detail_Fragmentxml_mainAct_ID"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".28"
class="com.knowledgeflex.lpm_qrt.Option_Fragment3">
</fragment>
<fragment
android:id="@+id/map_Fragmentxml_mainAct_ID"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".92"
class="com.knowledgeflex.lpm_qrt.Map_Fragment4">
</fragment>
</LinearLayout>
时出现类型不匹配错误。如何解决?
答案 0 :(得分:2)
Zxc
和Baz
是不相关的类型,您不能将其中一个分配给另一个。
如果您希望Abc
能够使用“基类”Foo
存储它们,请使用trait object,例如
struct Abc {
f: Box<Foo>
}
// ^ Abc is not a template.
impl Abc {
fn bared<B: Bar + 'static>(&mut self, b: B) {
self.f = Box::new(b);
}
// ^ maybe you want to change it to take `b: Box<Bar>`
// it depends on how you want to expose the API.
}
fn main() {
let mut abc = Abc { f: Box::new(Zxc) };
abc.bared(Baz);
}
然而,Rust的OOP范例与Java不同,特征对象可能不是最佳解决方案。也许你应该展示你想要解决的实际问题。
答案 1 :(得分:1)
您尚未声明可以存储任何实现Foo
的内容的类型;你已经宣布了一种用于制作类型的工厂,它可以存储实现Foo
类型的任何特定对象。
完成一些代码:
struct Abc<F: Foo> {
f: F
}
这大致翻译为“给我一个实现F
的{{1}}类型”,我将创建一个存储一个“{1}}的类型。”
使用时:
Foo
添加回编译器推断的类型:
Abc<F>
因此let mut abc = Abc { f: Box::new(Zxc) };
的类型为let mut abc: Abc<Zxc> = Abc { f: Box::new(Zxc) };
- 不是 abc.f
。
所以现在你有Box<Zxc>
- 不是通用的Box<Foo>
(在指定类型参数Abc<Zxc>
之前,你不能创建具体的对象。)
现在应该清楚为什么不能将它与Abc
一起使用。
现在出现实际错误:
F
错误实际上不是对Baz
的调用;这是定义:
<anon>:17:18: 17:19 error: mismatched types: expected `F`,
found `B` (expected type parameter,
found a different type parameter) [E0308] <anon>:17 self.f = b;
^ <anon>:17:18: 17:19 help: see the detailed explanation for E0308 error: aborting due to previous error
此方法表示它采用任何类型abc.bared
,它实现// In the impl of Abc<F>
fn bared<B: Bar + 'static>(&mut self, b: B) {
self.f = Box::new(b);
}
但可能与B
完全无关,并将其存储在Bar
中,这是F
类型为self.f
。您无法将Box<F>
分配给Box<B>
,因为它们的类型不同。
正如@kennytm所说,你可以通过使字段成为特征对象(Box<F>
)来存储不同的类型,这与其他语言中的基类指针更相似。
答案 2 :(得分:0)
除了其他答案之外,如果您尝试构建构建器模式,则可能需要更改bared
方法以按值获取构建器,然后返回新类型:
impl<F: Foo> Abc<F> {
fn bared<B: Bar>(self, b: B) -> Abc<B> {
Abc { f: b }
}
}
这会在调用Abc<Zxc>
时将具体类型从Abc<Baz>
更改为bared
:
let abc = Abc { f: Zxc };
let def = abc.bared(Baz);