“分类"铁锈的性状 [英] "Subclassing" traits in Rust

查看:101
本文介绍了“分类"铁锈的性状的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到的情况是,我的几个结构应实现多个特征,但所有结构都至少实现一个共同的特征.当我掌握了这些结构的混合包时,我想将它们全部视为具有共同特征:将它们作为键入该特征的方法参数传递,将它们存储在为此特征键入的集合中,等等.

I have a situation where several of my structs should implement multiple traits, but all of them implement at least one trait in common. When I get hold of a mixed bag of these structs, I want to treat them all as being of the common trait: pass them as method parameters typed to that trait, store them in collections typed for that trait, etc.

我一直无法弄清楚该怎么做.这是我尝试按照此处建议的方式执行的一些代码,但是无法编译:

I haven't been able to figure out how to do it. Here is some code where I try to do the way it was suggested here, but it fails to compile:

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实现.

Essentially, it still can't find the ThingWithKeys implementation inside the XxxWithKeys implementations.

推荐答案

Rust中的特质继承不同于OOP继承.特性继承只是指定需求的一种方式. trait B: A 并不暗示:如果类型实现了B,它将自动实现A;这意味着,如果类型实现B,则它必须实现 A.这也意味着,如果实现了B,则必须分别实现A .

Trait inheritance in Rust differs from OOP inheritance. Trait inheritance is just a way to specify requirements. trait B: A does not imply that if a type implements B it will automatically implement A; it means that if a type implements B it must implement A. This also means that you will have to implement A separately if B is implemented.

例如,

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并且又实现了AB(从而避免为该类型手动实现C),则可以使用通用的impl:

However, if want a type to automatically implement C if it implements A and B (and thereby avoiding manually implementing C for that type), then you can use a generic impl:

impl<T: A + B> C for T {}

在您的示例中,这表示为

In your example, this translates to

impl<T: Florida + ThingWithKeys> FloridaWithKeys for T {}

有关更多信息,请参见此论坛主题

Take a look at this forum thread for more information.

顺便说一句,您不需要为PianoWithKeys绑定ThingWithKeys,因为Piano已经需要ThingWithKeys.

As an aside, you do not require the ThingWithKeys bound for PianoWithKeys as Piano already requires ThingWithKeys.

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

EDIT (in accordance with your comment and question edit):

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

As stated before, trait inheritance in Rust differs from OOP inheritance. Even if trait B: A, you cannot coerce a trait object of B to a trait object of A. If you have no other choice but to pass the trait objects as is to the method, using generics works:

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

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

The generic method will work for type references (non trait objects) too.

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

这篇关于“分类"铁锈的性状的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆