再论枚举
实现枚举的方法
Rust的enum也可以用impl实现方法。
enum Message {
Quit,
ChangeColor(i32, i32, i32),
Move { x: i32, y: i32 },
Write(String)
}
impl Message {
fn call(&self) {
match self {
&Message::Quit => println!("Quit"),
&Message::Move { x, y } => println!("Move: {},{}", x, y),
&Message::ChangeColor(x, y, z) => println!("ChangeColor: {},{},{}", x, y, z),
&Message::Write(ref s) => println!("Write {}",s)
}
}
}
fn main() {
let msg = Message::Move{x:1,y:2};
msg.call(); // 打印:Move: 1,2
}
上例中的Message的call方法也可以这样定义:
impl Message {
fn call(&self) {
match *self {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move: {},{}", x, y),
Message::ChangeColor(x, y, z) => println!("ChangeColor: {},{},{}", x, y, z),
Message::Write(ref s) => println!("Write {}",s)
}
}
}
推荐使用第二种写法(官方文档是这样写的)。
就是不能写成这样:
match self {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move: {},{}", x, y),
Message::ChangeColor(x, y, z) => println!("ChangeColor: {},{},{}", x, y, z),
}
}
}
self本身是一个引用类型,即&Message,所以放到match语句中需要与匹配的类型对应起来。
- self 匹配 &Message
- *self 匹配 Message
值得注意,match非常简单的就匹配了i32这种Copy类型的数据。对String这种非Copy类型在match中需要使用ref
显式引用。
Rust的enum为何强大?
首先,我们要明白enum什么样的数据结构?
enum是一种类型类。其中包含了各种子类型。
其他语言,比如Java,每种子类型所拥有的字段及方法必须一样。这显然限制了枚举的概念。
例:
public enum Person {
Male("man"),Female("woman");
private String name;
private Person(String name) {
this.name = name;
}
public String getName() {
if(this == Male){
return "he is a " + this.name;
} else if(this == Female) {
return "she is a " + this.name;
} else {
return "it is not human";
}
}
}
可以看到Java的枚举类的不同枚举类型即便是“相同方法不同行为”,实现起来都非常费力。
再看Rust,Rust的enum的元素可以是不同的复合类型,这比Java及其他语言强大多了。在enum的方法中使用模式匹配,在代码层面更加清晰简单。
例:
enum Person {
Male,
Female
}
impl Person {
fn name(&self) -> String {
match *self {
Person::Male => String::from("he is a man"),
Person::Female => String::from("she is a woman"),
_ => String::from("it is not human") // 这行可以不需要。
}
}
}
fn main() {
let p = Person::Female;
let s = p.name();
println!("{}",s); // 打印:she is a woman
}