Struct 作为 Rust 语言的基础组成, 需要熟悉其用法.

Rust 中的 Struct

Struct 主要就是语法上的内容, 列于如下:

  1. 定义 struct 的示例:

    rust
    struct User {
        active: bool,
        username: String,
        email: String,
        sign_in_count: u64,
    }
  2. 创建 struct 对象:

    rust
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
  3. 创建可变对象(Rust 没有单个属性可变的语法):

    rust
    let mut user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    
    user1.email = String::from("anotheremail@example.com");
  4. struct 的“构造函数”定义:

    rust
    fn new(email: String, username: String) -> User {
        User {
            email: email,
            username: username,
            active: true,
            sign_in_count: 1,
        }
    }
  5. 属性赋值的简单语法:

    rust
    fn new(email: String, username: String) -> User {
        User {
            email,
            username,
            active: true,
            sign_in_count: 1,
        }
    }
  6. 根据一个 struct 创建新 struct 语法:

    rust
    // 即只修改想要的, 其余部分展开到新 struct 中, 展开需要放到末尾写
    let user2 = User {
        email: String::from("another@example.com"),
        ..user1
    };

    注意上面的 user1 被 move 了, 因为剩余被展开的成员中包含 String(堆内存分配的), 如果上述 username 也是自己创建的新值, 则不会对 user1 move, 因为剩余的成员都是栈内存拷贝的.

  7. Tuple struct 的语法:

    rust
    struct Color(i32, i32, i32);
    struct Point(i32, i32, i32);
    
    fn main() {
        let black = Color(0, 0, 0);
        let origin = Point(0, 0, 0);
    }

    使用 Tuple struct 的目的是区分不同类型的 Tuple(即便 Tuple 中的成员都相同), 且同样可以使用.语法来访问成员.

  8. Unit Like struct 的语法:

    rust
    struct AlwaysEqual;
    
    fn main() {
        let subject = AlwaysEqual;
    }

    后续可以看到它的使用, 比如可以通过这种零数据的 struct 实现任意 trait.

Struct 的成员 Ownership 概述

struct 内部成员的 owner 就是该 struct.

比如上面定义过的 User struct, 在它里面选择的是 String 成员而非 &str 引用成员. 原因是想让 struct 对该成员持有, 且成员生命期就和 struct 的生命期一致了.

当然 struct 也可以有引用成员, 这就需要牵扯到生命期标记, 之后再讲.

struct 方法实现

主要还是语法:

  1. 方法定义和使用:

    rust
    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }
    
    impl Rectangle {
        fn area(&self) -> u32 {
            self.width * self.height
        }
    }
    
    fn main() {
        let rect1 = Rectangle {
            width: 30,
            height: 50,
        };
    
        println!(
            "The area of the rectangle is {} square pixels.",
            rect1.area()
        );
    }

    方法参数第一个总是如下的其中一个:

    • self: 若 struct 不是 Copy 实现, 会将 struct 对象 move 到方法中(获取 ownership)
    • &self: 仅不可变引用该 struct 对象
    • &mut self: 该 struct 对象的可变引用
  2. 在方法调用时, 由于 Rust 有自动的引用和解引用(自动添加 &, &mut, *), 因此如果是 &self 的方法, 也无需手动写类似 (&user).some_method(), 而是直接 user.some_method() 即可.

  3. 关联函数: 即其他语言中类方法.

rust
impl Rectangle {
    fn square(size: u32) -> Self {
        Self {
            width: size,
            height: size,
        }
    }
}
  1. 一个 struct 可以有多个 impl 块, 这样可以非常方便地分离多组方法实现.