• 枚举
    • 构造器作为函数(Constructors as functions)

    枚举

    enums.md


    commit ccb1d87d6faa9ff528d22b96595a0e2cbb16c0f2

    Rust 中的一个enum是一个代表数个可能变量的数据的类型。enum中的每个变量都可选是否关联数据:

    1. enum Message {
    2. Quit,
    3. ChangeColor(i32, i32, i32),
    4. Move { x: i32, y: i32 },
    5. Write(String),
    6. }

    定义变量的语法与用来定义结构体的语法类似:你可以有不带数据的变量(像类单元结构体),带有命名数据的变量,和带有未命名数据的变量(像元组结构体)。然而,不像单独的结构体定义,一个enum是一个单独的类型。一个枚举的值可以匹配任何一个变量。因为这个原因,枚举有时被叫做“集合类型”:枚举可能值的集合是每一个变量可能值的集合的总和。

    我们使用::语法来使用每个变量的名字:它们包含在enum名字自身中。这样的话,以下的情况都是可行的:

    1. # enum Message {
    2. # Move { x: i32, y: i32 },
    3. # }
    4. let x: Message = Message::Move { x: 3, y: 4 };
    5. enum BoardGameTurn {
    6. Move { squares: i32 },
    7. Pass,
    8. }
    9. let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 };

    这两个变量都叫做Move,不过他们包含在枚举名字中,他们可以无冲突的使用。

    枚举类型的一个值包含它是哪个变量的信息,以及任何与变量相关的数据。这有时被作为一个“标记的联合”被提及。因为数据包括一个“标签”表明它的类型是什么。编译器使用这个信息来确保安全的访问枚举中的数据。例如,我们不能简单的尝试解构一个枚举值,就像它是其中一个可能的变体那样:

    1. fn process_color_change(msg: Message) {
    2. let Message::ChangeColor(r, g, b) = msg; // This causes a compile-time error.
    3. }

    不支持这些操作(比较操作)可能看起来更像限制。不过这是一个我们可以克服的限制。有两种方法:我们自己实现相等(比较),或通过match 表达式模式匹配变量,你会在下一部分学到它。我们还不够了解Rust如何实现相等,不过我们会在特性找到它们。

    构造器作为函数(Constructors as functions)

    一个枚举的构造器总是可以像函数一样使用。例如:

    1. # enum Message {
    2. # Write(String),
    3. # }
    4. let m = Message::Write("Hello, world".to_string());

    与下面是一样的:

    1. # enum Message {
    2. # Write(String),
    3. # }
    4. fn foo(x: String) -> Message {
    5. Message::Write(x)
    6. }
    7. let x = foo("Hello, world".to_string());

    这对我们没有什么直接的帮助,直到我们要用到闭包时,这时我们要考虑将函数作为参数传递给其他函数。例如,使用迭代器,我们可以这样把一个String的vector转换为一个Message::Write的vector:

    1. # enum Message {
    2. # Write(String),
    3. # }
    4. let v = vec!["Hello".to_string(), "World".to_string()];
    5. let v1: Vec<Message> = v.into_iter().map(Message::Write).collect();