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());
}
我想我误解了枚举的目的。
我希望实施 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());
}