enums.md
commit 31e39cd05c9b28c78b087aa9314f246b0b0b5cfa
Rust 中的一個enum
是一個代表數(shù)個可能變量的數(shù)據(jù)的類型。每個變量都可選是否關(guān)聯(lián)數(shù)據(jù):
enum Message {
Quit,
ChangeColor(i32, i32, i32),
Move { x: i32, y: i32 },
Write(String),
}
定義變量的語法與用來定義結(jié)構(gòu)體的語法類似:你可以有不帶數(shù)據(jù)的變量(像類單元結(jié)構(gòu)體),帶有命名數(shù)據(jù)的變量,和帶有未命名數(shù)據(jù)的變量(像元組結(jié)構(gòu)體)。然而,不像單獨(dú)的結(jié)構(gòu)體定義,一個enum
是一個單獨(dú)的類型。一個枚舉的值可以匹配任何一個變量。因為這個原因,枚舉有時被叫做“集合類型”:枚舉可能值的集合是每一個變量可能值的集合的總和。
我們使用::
語法來使用每個變量的名字:它們包含在enum
名字自身中。這樣的話,以下的情況都是可行的:
# enum Message {
# Move { x: i32, y: i32 },
# }
let x: Message = Message::Move { x: 3, y: 4 };
enum BoardGameTurn {
Move { squares: i32 },
Pass,
}
let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 };
這兩個變量都叫做Move
,不過他們包含在枚舉名字中,他們可以無沖突的使用。
枚舉類型的一個值包含它是哪個變量的信息,以及任何與變量相關(guān)的數(shù)據(jù)。這有時被作為一個“標(biāo)記的聯(lián)合”被提及。因為數(shù)據(jù)包括一個“標(biāo)簽”表明它的類型是什么。編譯器使用這個信息來確保安全的訪問枚舉中的數(shù)據(jù)。例如,我們不能簡單的嘗試解構(gòu)一個枚舉值,就像它是其中一個可能的變體那樣:
fn process_color_change(msg: Message) {
let Message::ChangeColor(r, g, b) = msg; // compile-time error
}
不支持這些操作(比較操作)可能看起來更像限制。不過這是一個我們可以克服的限制。有兩種方法:我們自己實現(xiàn)相等(比較),或通過[match
](Match 匹配.md)表達(dá)式模式匹配變量,你會在下一部分學(xué)到它。我們還不夠了解Rust如何實現(xiàn)相等,不過我們會在特性找到它們。
一個枚舉的構(gòu)造器總是可以像函數(shù)一樣使用。例如:
# enum Message {
# Write(String),
# }
let m = Message::Write("Hello, world".to_string());
與下面是一樣的:
# enum Message {
# Write(String),
# }
fn foo(x: String) -> Message {
Message::Write(x)
}
let x = foo("Hello, world".to_string());
這對我們沒有什么直接的幫助,直到我們要用到[閉包](Closures 閉包.md)時,這時我們要考慮將函數(shù)作為參數(shù)傳遞給其他函數(shù)。例如,使用[迭代器](Iterators 迭代器.md),我們可以這樣把一個String
的vector轉(zhuǎn)換為一個Message::Write
的vector:
# enum Message {
# Write(String),
# }
let v = vec!["Hello".to_string(), "World".to_string()];
let v1: Vec<Message> = v.into_iter().map(Message::Write).collect();