如何让调用者看到方法的特征实现?

How do I make a caller see the trait implementation of a method?

使用代码:

trait Msg {
    fn apply_to_state(&self, state: &mut State);
}

trait ApplicableToStateOne: Msg {
    fn apply_to_state(&self, state: &mut State) {
        match state {
            State::StateOne(s) => {
                self.apply_to_state_one(s) 
            }
            _ => {
                //TODO: return an error
            }
        }
    }
    fn apply_to_state_one(&self, state_one: &mut StateOne);
}

#[derive(Debug, Clone)]
pub struct MsgA {
    pub field_a: u8,
}

impl Msg for MsgA {}
impl ApplicableToStateOne for MsgA {
    fn apply_to_state_one(&self, state_one: &mut StateOne) {
        state_one.one_special += 31; // just a mutability test
    }
}

// this is a stub for receiving different kinds of messages from the network
fn recv() -> Box<dyn Msg> {
    Box::new(MsgA { field_a: 42 })
}

fn main() {
    let mut state = State::StateOne(StateOne { common: 0, one_special: 1 });
    for _ in 0..100 { // this would be loop, but that makes the playground timeout
        let incoming = recv(); // this would block
        incoming.apply_to_state(&mut state)
    }
}

(操场:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7c89a2bbc765380fc002864e2be80e55

编译器抱怨:

error[E0046]: not all trait items implemented, missing: `apply_to_state`
  --> src/bin/sandbox6.rs:83:1
   |
2  |     fn apply_to_state(&self, state: &mut State);
   |     -------------------------------------------- `apply_to_state` from trait
...
83 | impl Msg for MsgA {}
   | ^^^^^^^^^^^^^^^^^ missing `apply_to_state` in implementation

在我(显然有缺陷)的理解中,我本以为会调用 apply_to_statetrait ApplicableToStateOne 实现。

我怎样才能做到这一点?


更新:

更抽象地说,这个问题是关于:

  1. 从网络接收一个装箱的超特征对象,然后
  2. 找出它有哪个子特征,最后
  3. 调用适合子特征的方法(可能以某种方式通过超特征)。

这一切都可以完成,相当冗长,使用枚举而不是特征,但这增加了枚举的层次结构。

枚举层次结构不好,因为:

考虑要链接到 Trait 而不是对象本身的每个方法。 检查这个更简单的例子:

trait Foo {
    fn foo(&self) -> &'static str;
}

trait FooPrime {
    fn foo(&self) -> &'static str;
}

struct Bar {}

impl Foo for Bar {
    fn foo(&self) -> &'static str {
        "foo"
    }
}

impl FooPrime for Bar {
  fn foo(&self) -> &'static str {
        "foo prime"
    }  
}

fn main() {
    let bar = Bar{};
    println!("{} : {}", bar.foo(), bar.foo());
}

编译时出现以下错误:

   Compiling playground v0.0.1 (/playground)
error[E0034]: multiple applicable items in scope
  --> src/main.rs:25:29
   |
25 |     println!("{} : {}", bar.foo(), bar.foo());
   |                             ^^^ multiple `foo` found
   |
note: candidate #1 is defined in an impl of the trait `Foo` for the type `Bar`
  --> src/main.rs:12:5
   |
12 |     fn foo(&self) -> &'static str {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `FooPrime` for the type `Bar`
  --> src/main.rs:18:3
   |
18 |   fn foo(&self) -> &'static str {
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #1
   |
25 |     println!("{} : {}", Foo::foo(&bar), bar.foo());
   |                         ^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #2
   |
25 |     println!("{} : {}", FooPrime::foo(&bar), bar.foo());
   |                         ^^^^^^^^^^^^^^^^^^^

error[E0034]: multiple applicable items in scope
  --> src/main.rs:25:40
   |
25 |     println!("{} : {}", bar.foo(), bar.foo());
   |                                        ^^^ multiple `foo` found
   |
note: candidate #1 is defined in an impl of the trait `Foo` for the type `Bar`
  --> src/main.rs:12:5
   |
12 |     fn foo(&self) -> &'static str {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `FooPrime` for the type `Bar`
  --> src/main.rs:18:3
   |
18 |   fn foo(&self) -> &'static str {
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #1
   |
25 |     println!("{} : {}", bar.foo(), Foo::foo(&bar));
   |                                    ^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #2
   |
25 |     println!("{} : {}", bar.foo(), FooPrime::foo(&bar));

我们需要明确告诉编译器使用哪个方法:

fn main() {
    let bar = Bar{};
    println!("{} : {}", Foo::foo(&bar), FooPrime::foo(&bar));
}

Playground

出于同样的原因,在您的代码中未使用其他特征的方法,因为它不是先前特征的一部分。 这是一个link to the book

您可能希望使用 supertrait 功能来创建基于“父”特征的另一个特征的默认实现:

trait FooPrime : Foo {
    fn foo(&self) -> &'static str {
        Foo::foo(self)
    }
}

Playground

您可以使用泛型来为所有实现 ApplicableToStateOne:

的东西实现 Msg
struct State {}

trait Msg {
    fn apply_to_state(&self, state: &mut State);
}

trait ApplicableToStateOne: Msg {
    fn apply_to_state_one(&self, state: &mut State) {
        todo!();
    }
}

impl<T: ApplicableToStateOne> Msg for T {
    fn apply_to_state(&self, state: &mut State) {
        self.apply_to_state_one (state);
    }
}

#[derive(Debug, Clone)]
pub struct MsgA {
    pub field_a: u8,
}

impl ApplicableToStateOne for MsgA {}
// No need to implement Msg explicitly for MsgA

Playground