Rust 枚举可以使用在其变体之一上实现的方法吗?

Can a Rust enum use methods implemented on one of its variants?

我想我误解了枚举的目的。

我希望实施 XML DOM 进行练习。 DOM 个节点都有与其关联的方法列表,但某些节点(例如文档节点)具有其他节点不可用的其他方法。

我希望在枚举上设置所有主要方法,然后变体将具有特定于它们的方法,但似乎方法变体在枚举上不可调用,但继续可调用在参数上。

#[derive(Clone, Debug, Copy)]
enum MyEnum {
    MyType(MyType),
}

impl MyEnum {
    pub fn do_a_thing(&self) -> i32 {
        // Some code here
        return 1;
    }
}

#[derive(Clone, Debug, Copy)]
pub struct MyType {}

impl MyType {
    pub fn do_another_thing(self) -> i32 {
        // Some more code here
        return 2;
    }
}

fn main() {
    let x = MyEnum::MyType(MyType {});
    println!("{:?}", x);
    println!("I can call do_a_thing, it is {}", x.do_a_thing());
    println!(
        "Why can't I call do_another_thing? {}",
        x.do_another_thing()
    );
}

这很好用,但我的直觉告诉我我走错了路:

impl MyEnum {
    pub fn do_a_thing(&self) -> i32 {
        // Some code here
        return 1;
    }

    pub fn do_another_thing(self) -> i32 {
        match self {
            MyEnum::MyType(MT) => MT.do_another_thing(),
        }
    }
}

我应该如何实施?

您正在使用枚举,因此您可能会在某个时候添加更多变体(否则,您为什么要使用枚举,对吗?)。

当 Rust 看到一个类型为枚举的值时,在编译时它假定该值可以是枚举的任何变体,因此在您检查其类型之前,它不会让您调用任何变体的方法.

要做到这一点很容易,正如您在问题中已经表明的那样:

match self {
    MyEnum::MyType(t) => t.do_another_thing()
}

如果您只想检查一个变体,您可能有兴趣知道还有 if let

let x = MyEnum::MyType(MyType{});
if let MyEnum::MyType(t) = x {
    t.do_another_thing();
}

您可能还希望拥有可在所有变体上调用的方法,在这种情况下,您需要像上面那样直接在 enum 上实现该方法,或者使用由枚举实现的特征,这可能使您的代码看起来像大多数其他语言一样更具多态性(其中会有一个节点接口)。

这将使您的代码进入主要工作。

它可能看起来像这样:

#[derive(Clone, Debug, Copy)]
enum MyEnum {
    MyType(MyType)
}

impl MyEnum {
    pub fn do_a_thing(&self) -> i32{
        // Some code here
        return 1
    }
}

#[derive(Clone, Debug, Copy)]
pub struct MyType {

}

trait MyTrait {
   fn do_another_thing(&self) -> i32;
}

impl MyTrait for MyEnum {
    fn do_another_thing(&self) -> i32 {
        // Some more code here
        return 2
    }
}

fn main() {

    let x = MyEnum::MyType(MyType{});
    println!("{:?}",x);
    println!("I can call do_a_thing, it is {}", x.do_a_thing());
    println!("Why can't I call do_another_thing? {}", x.do_another_thing());

}