Rust中的“子类化”特征

Dan*_*ebe 3 polymorphism traits 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 ());
}
Run Code Online (Sandbox Code Playgroud)

这是编译错误:

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 ());
}
Run Code Online (Sandbox Code Playgroud)

从本质上讲,它仍然无法在XxxWithKeys实现中找到ThingWithKeys实现。

Evi*_*Tak 9

Rust中的特质继承不同于OOP继承。特性继承只是指定需求的一种方式。trait B: A 并不意味着如果一个类型实现,B它会自动实现A; 这意味着,如果类型实现,B必须实现 A。这也意味着,如果已实施,则必须A 单独B实施。

举个例子,

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;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果希望某个类型在C实现A和时自动实现B(从而避免手动C为该类型实现),则可以使用泛型impl

impl<T: A + B> C for T {}
Run Code Online (Sandbox Code Playgroud)

在您的示例中,这转化为

impl<T: Florida + ThingWithKeys> FloridaWithKeys for T {}
Run Code Online (Sandbox Code Playgroud)

查看此论坛主题以获取更多信息。

顺便说一句,你不需要ThingWithKeys开往PianoWithKeys作为Piano已经要求ThingWithKeys

编辑(根据您的评论和问题编辑):

如前所述,Rust中的特征继承不同于OOP继承。即使trait B: A,您也无法将的特质对象强制BA。如果您别无选择,只能将特质对象按原样传递给方法,则使用泛型可以:

fn use_keys<T: ThingWithKeys + ?Sized>(thing_with_keys: &T) {
    println! ("{}", thing_with_keys.use_keys ());
}
Run Code Online (Sandbox Code Playgroud)

通用方法也适用于类型引用(非特征对象)。

还要检查:Rust为什么不支持特征对象上载?