结构体和枚举

结构体

在实例化一个结构体时将它整体标记为可变的,但是 Rust 不允许我们将结构体的某个字段专门指定为可变的。一旦实例可变,那么实例中的所有字段都将是可变的。

  • 定义

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}
  • 创建

  1. 初始化实例时,每个字段都需要进行初始化

  2. 初始化时的字段顺序不需要和结构体定义时的顺序一致

#![allow(unused)]
fn main() {
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
}

当函数参数和结构体字段同名时,可以直接使用缩略的方式进行初始化,跟 TypeScript 中一模一样。

#![allow(unused)]
fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}
  • 更新语法

let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    ..user1
};

.. 语法表明凡是我们没有显示声明的字段,全部从 user1 中自动获取。需要注意的是 ..user1 必须在结构体的尾部使用。

值得注意的是:username 所有权被转移给了 user2,导致了 user1 无法再被使用,但是并不代表 user1 内部的其它字段不能被继续使用。

  • 元组结构体

#![allow(unused)]
fn main() {
    struct Color(i32, i32, i32);
    struct Point(i32, i32, i32);

    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
}
  • 空struct

#![allow(unused)]
fn main() {
struct AlwaysEqual;

let subject = AlwaysEqual;

// 我们不关心 AlwaysEqual 的字段数据,只关心它的行为,因此将它声明为单元结构体,然后再为它实现某个特征
impl SomeTrait for AlwaysEqual {

}
}

如果想在结构体中使用一个引用,就必须加上生命周期,否则就会报错。

  • #[derive(Debug)] 打印结构体

{:?},{:#?}

dbg!宏:拿走表达式的所有权,打印出相应的文件名、行号等 debug 信息,最终还会把表达式值的所有权返回

当解构一个变量时,可以同时使用 move 和引用模式绑定的方式。当这么做时,部分 move 就会发生:变量中一部分的所有权被转移给其它变量,而另一部分我们获取了它的引用。

在这种情况下,原变量将无法再被使用,但是它没有转移所有权的那一部分依然可以使用,也就是之前被引用的那部分。

枚举

任何类型的数据都可以放入枚举成员中: 例如字符串、数值、结构体甚至另一个枚举。

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn main() {
    let m1 = Message::Quit;
    let m2 = Message::Move{x:1,y:1};
    let m3 = Message::ChangeColor(255,255,0);
}

#![allow(unused)]
fn main() {
struct QuitMessage; // 单元结构体
struct MoveMessage {
    x: i32,
    y: i32,
}
struct WriteMessage(String); // 元组结构体
struct ChangeColorMessage(i32, i32, i32); // 元组结构体
}
  • Quit 没有任何关联数据

  • Move 包含一个匿名结构体

  • Write 包含一个 String 字符串

  • ChangeColor 包含三个 i32

从代码规范角度来看,枚举的实现更简洁,代码内聚性更强,不像结构体的实现,分散在各个地方。

  • Option 枚举用于处理空值

Rust 吸取了众多教训,决定抛弃 null,而改为使用 Option 枚举变量来表述这种结果。

Option 枚举包含两个成员,一个成员表示含有值:Some(T), 另一个表示没有值:None


#![allow(unused)]
enum Option<T> {
    Some(T),
    None,
}

其中 T 是泛型参数,Some(T)表示该枚举成员的数据类型是 T,换句话说,Some 可以包含任何类型的数据。

只要一个值不是 Option<T> 类型,你就 可以 安全的认定它的值不为空。这是 Rust 的一个经过深思熟虑的设计决策,来限制空值的泛滥以增加 Rust 代码的安全性。


#![allow(unused)]
fn main() {
fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1),
    }
}

let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
}

plus_one 通过 match 来处理不同 Option 的情况。

Last updated