"Subclassing" Rust 中的特征
"Subclassing" traits in Rust
我有这样一种情况,我的几个结构应该实现多个特征,但它们都至少实现了一个共同特征。当我掌握这些结构的混合包时,我想将它们全部视为具有共同特征:将它们作为类型为该特征的方法参数传递,将它们存储在为该特征类型的集合中,等等。
我还不知道该怎么做。这是我尝试按照此处建议的方式执行的一些代码,但无法编译:
trait ThingWithKeys {
fn use_keys (&self) -> String;
}
//////
trait CorrectionsOfficer {
fn hitch_up_pants (&self) -> String;
}
trait CorrectionsOfficerWithKeys: ThingWithKeys + CorrectionsOfficer {}
struct CorrectionsOfficerReal {}
impl ThingWithKeys for CorrectionsOfficerReal {
fn use_keys (&self) -> String {
String::from ("Clank, clank")
}
}
impl CorrectionsOfficer for CorrectionsOfficerReal {
fn hitch_up_pants (&self) -> String {
String::from ("Grunt")
}
}
impl <T: ThingWithKeys + CorrectionsOfficer> CorrectionsOfficerWithKeys for T {}
//////
trait Piano {
fn close_lid (&self) -> String;
}
trait PianoWithKeys: Piano + ThingWithKeys {}
struct PianoReal {}
impl ThingWithKeys for PianoReal {
fn use_keys (&self) -> String {
String::from ("Tinkle, tinkle")
}
}
impl Piano for PianoReal {
fn close_lid (&self) -> String {
String::from ("Bang!")
}
}
impl <T: ThingWithKeys + Piano> PianoWithKeys for T {}
//////
trait Florida {
fn hurricane (&self) -> String;
}
trait FloridaWithKeys: ThingWithKeys + Florida {}
struct FloridaReal {}
impl ThingWithKeys for FloridaReal {
fn use_keys (&self) -> String {
String::from ("Another margarita, please")
}
}
impl Florida for FloridaReal {
fn hurricane (&self) -> String {
String::from ("Ho-hum...")
}
}
impl <T: ThingWithKeys + Florida> FloridaWithKeys for T {}
//////
fn main() {
let corrections_officer_ref: &CorrectionsOfficerWithKeys = &CorrectionsOfficerReal {};
let piano_ref: &PianoWithKeys = &PianoReal {};
let florida_ref: &FloridaWithKeys = &FloridaReal {};
use_keys (corrections_officer_ref);
use_keys (piano_ref);
use_keys (florida_ref);
}
fn use_keys (thing_with_keys: &ThingWithKeys) {
println! ("{}", thing_with_keys.use_keys ());
}
编译错误如下:
Compiling playground v0.0.1 (file:///playground)
error[E0308]: mismatched types
--> src/main.rs:80:19
|
80 | use_keys (corrections_officer_ref);
| ^^^^^^^^^^^^^^^^^^^^^^^ expected trait `ThingWithKeys`, found trait `CorrectionsOfficerWithKeys`
|
= note: expected type `&ThingWithKeys`
found type `&CorrectionsOfficerWithKeys`
error[E0308]: mismatched types
--> src/main.rs:81:19
|
81 | use_keys (piano_ref);
| ^^^^^^^^^ expected trait `ThingWithKeys`, found trait `PianoWithKeys`
|
= note: expected type `&ThingWithKeys`
found type `&PianoWithKeys`
error[E0308]: mismatched types
--> src/main.rs:82:19
|
82 | use_keys (florida_ref);
| ^^^^^^^^^^^ expected trait `ThingWithKeys`, found trait `FloridaWithKeys`
|
= note: expected type `&ThingWithKeys`
found type `&FloridaWithKeys`
error: aborting due to 3 previous errors
本质上,它仍然无法在 XxxWithKeys 实现中找到 ThingWithKeys 实现。
Rust 中的特征继承不同于 OOP 继承。特征继承只是一种指定要求的方式。 trait B: A
并不意味着 如果一个类型实现了 B
它将自动实现 A
;这意味着如果一个类型实现了 B
它 必须实现 A
。这也意味着如果实施了 B
,则必须单独实施 A
。
例如,
trait A {}
trait B: A {}
struct S;
impl B for S {}
// Commenting this line will result in a "trait bound unsatisfied" error
impl A for S {}
fn main() {
let _x: &B = &S;
}
但是,如果想要一个类型自动实现 C
如果它实现了 A
和 B
(从而避免为该类型手动实现 C
),那么您可以使用通用 impl
:
impl<T: A + B> C for T {}
在您的示例中,这转换为
impl<T: Florida + ThingWithKeys> FloridaWithKeys for T {}
查看 this forum thread 了解更多信息。
顺便说一句,您不需要 PianoWithKeys
的 ThingWithKeys
绑定,因为 Piano
已经需要 ThingWithKeys
.
编辑(根据您的评论和问题编辑):
如前所述,Rust 中的特征继承不同于 OOP 继承。即使 trait B: A
,你也不能将 B
的特征对象强制转换为A
的特征对象。如果您别无选择,只能将特征对象按原样传递给方法,那么使用泛型是可行的:
fn use_keys<T: ThingWithKeys + ?Sized>(thing_with_keys: &T) {
println! ("{}", thing_with_keys.use_keys ());
}
泛型方法也适用于类型引用(非特征对象)。
同时检查:Why doesn't Rust support trait object upcasting?
我有这样一种情况,我的几个结构应该实现多个特征,但它们都至少实现了一个共同特征。当我掌握这些结构的混合包时,我想将它们全部视为具有共同特征:将它们作为类型为该特征的方法参数传递,将它们存储在为该特征类型的集合中,等等。
我还不知道该怎么做。这是我尝试按照此处建议的方式执行的一些代码,但无法编译:
trait ThingWithKeys {
fn use_keys (&self) -> String;
}
//////
trait CorrectionsOfficer {
fn hitch_up_pants (&self) -> String;
}
trait CorrectionsOfficerWithKeys: ThingWithKeys + CorrectionsOfficer {}
struct CorrectionsOfficerReal {}
impl ThingWithKeys for CorrectionsOfficerReal {
fn use_keys (&self) -> String {
String::from ("Clank, clank")
}
}
impl CorrectionsOfficer for CorrectionsOfficerReal {
fn hitch_up_pants (&self) -> String {
String::from ("Grunt")
}
}
impl <T: ThingWithKeys + CorrectionsOfficer> CorrectionsOfficerWithKeys for T {}
//////
trait Piano {
fn close_lid (&self) -> String;
}
trait PianoWithKeys: Piano + ThingWithKeys {}
struct PianoReal {}
impl ThingWithKeys for PianoReal {
fn use_keys (&self) -> String {
String::from ("Tinkle, tinkle")
}
}
impl Piano for PianoReal {
fn close_lid (&self) -> String {
String::from ("Bang!")
}
}
impl <T: ThingWithKeys + Piano> PianoWithKeys for T {}
//////
trait Florida {
fn hurricane (&self) -> String;
}
trait FloridaWithKeys: ThingWithKeys + Florida {}
struct FloridaReal {}
impl ThingWithKeys for FloridaReal {
fn use_keys (&self) -> String {
String::from ("Another margarita, please")
}
}
impl Florida for FloridaReal {
fn hurricane (&self) -> String {
String::from ("Ho-hum...")
}
}
impl <T: ThingWithKeys + Florida> FloridaWithKeys for T {}
//////
fn main() {
let corrections_officer_ref: &CorrectionsOfficerWithKeys = &CorrectionsOfficerReal {};
let piano_ref: &PianoWithKeys = &PianoReal {};
let florida_ref: &FloridaWithKeys = &FloridaReal {};
use_keys (corrections_officer_ref);
use_keys (piano_ref);
use_keys (florida_ref);
}
fn use_keys (thing_with_keys: &ThingWithKeys) {
println! ("{}", thing_with_keys.use_keys ());
}
编译错误如下:
Compiling playground v0.0.1 (file:///playground)
error[E0308]: mismatched types
--> src/main.rs:80:19
|
80 | use_keys (corrections_officer_ref);
| ^^^^^^^^^^^^^^^^^^^^^^^ expected trait `ThingWithKeys`, found trait `CorrectionsOfficerWithKeys`
|
= note: expected type `&ThingWithKeys`
found type `&CorrectionsOfficerWithKeys`
error[E0308]: mismatched types
--> src/main.rs:81:19
|
81 | use_keys (piano_ref);
| ^^^^^^^^^ expected trait `ThingWithKeys`, found trait `PianoWithKeys`
|
= note: expected type `&ThingWithKeys`
found type `&PianoWithKeys`
error[E0308]: mismatched types
--> src/main.rs:82:19
|
82 | use_keys (florida_ref);
| ^^^^^^^^^^^ expected trait `ThingWithKeys`, found trait `FloridaWithKeys`
|
= note: expected type `&ThingWithKeys`
found type `&FloridaWithKeys`
error: aborting due to 3 previous errors
本质上,它仍然无法在 XxxWithKeys 实现中找到 ThingWithKeys 实现。
Rust 中的特征继承不同于 OOP 继承。特征继承只是一种指定要求的方式。 trait B: A
并不意味着 如果一个类型实现了 B
它将自动实现 A
;这意味着如果一个类型实现了 B
它 必须实现 A
。这也意味着如果实施了 B
,则必须单独实施 A
。
例如,
trait A {}
trait B: A {}
struct S;
impl B for S {}
// Commenting this line will result in a "trait bound unsatisfied" error
impl A for S {}
fn main() {
let _x: &B = &S;
}
但是,如果想要一个类型自动实现 C
如果它实现了 A
和 B
(从而避免为该类型手动实现 C
),那么您可以使用通用 impl
:
impl<T: A + B> C for T {}
在您的示例中,这转换为
impl<T: Florida + ThingWithKeys> FloridaWithKeys for T {}
查看 this forum thread 了解更多信息。
顺便说一句,您不需要 PianoWithKeys
的 ThingWithKeys
绑定,因为 Piano
已经需要 ThingWithKeys
.
编辑(根据您的评论和问题编辑):
如前所述,Rust 中的特征继承不同于 OOP 继承。即使 trait B: A
,你也不能将 B
的特征对象强制转换为A
的特征对象。如果您别无选择,只能将特征对象按原样传递给方法,那么使用泛型是可行的:
fn use_keys<T: ThingWithKeys + ?Sized>(thing_with_keys: &T) {
println! ("{}", thing_with_keys.use_keys ());
}
泛型方法也适用于类型引用(非特征对象)。
同时检查:Why doesn't Rust support trait object upcasting?