# Rust 中的结构体 (Struct)

结构体(Struct)是一种自定义数据类型,允许你将多个相关的值组合在一起,并为每个值命名。

# 定义与实例化

使用 struct 关键字来定义一个结构体,并在花括号中为所有字段指定名称和类型。

// 定义一个结构体
struct User {
    name: String,
    age: u8,
    email: String,
}

// 创建结构体实例
let user1 = User {
    name: String::from("Alice"),
    age: 30,
    email: String::from("alice@example.com"),
};

# 结构体更新语法

当你想要基于另一个结构体实例来创建一个新实例,并且只更改其中少量字段时,可以使用 .. 语法。这会使用未显式设置的字段的旧实例中的值。

let user2 = User {
    email: String::from("hello@gmail.com"),
    ..user1 // user1 的 name 和 age 字段会被用于 user2
};

# 元组结构体 (Tuple Structs)

元组结构体是一种类似于元组的结构体,其字段没有名称,只有类型。

struct UserTuple(String, u8, String);
struct UserTuple2(String, u8, String);

let user3 = UserTuple(String::from("Bob"), 25, String::from("bob@example.com"));

注意:即使两个元组结构体具有完全相同的字段类型,它们也是不同的类型。例如,UserTupleUserTuple2 是不可互换的。

# 使用 derive trait 增加功能

我们可以通过 #[derive] 注解为结构体自动实现某些 trait。例如,Debug trait 允许我们使用 {:?}{:#?} 格式化字符串来打印结构体实例,这对于调试非常有用。

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

let rect1 = Rectangle {
    width: 30,
    height: 50,
};

// 使用 Debug trait 进行打印
println!("{:#?}", rect1);

# 结构体方法

方法与函数类似,但它们在结构体(或枚举、trait对象)的上下文中定义,并且它们的第一个参数总是 self,代表调用该方法的结构体实例。

# 定义方法

方法在 impl (implementation) 块中定义。

impl Rectangle {
    // 方法的第一个参数永远是 self

    // 计算面积,该方法借用了 Rectangle 实例的不可变引用
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // 判断一个矩形能否容纳另一个矩形
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width >= other.width && self.height >= other.height
    }
    
    // 可变方法,借用了实例的可变引用,可以修改实例的字段
    fn set_width(&mut self, width: u32) {
        self.width = width;
    }
}
self 类型 描述
&self 对实例的不可变借用,用于只读操作。
&mut self 对实例的可变借用,用于修改实例的状态。
self 获取实例的所有权,将其移出调用者。

调用可变方法:

可变方法必须由一个可变的结构体实例来调用。

let mut rect3 = Rectangle { width: 10, height: 20 };
rect3.set_width(15);
println!("Rectangle 3 的宽度是 {}", rect3.width);

# 关联函数 (Associated Functions)

impl 块中也可以定义不以 self 作为第一个参数的函数,这被称为关联函数。它们通常用作构造函数。

impl Rectangle {
    // 这是一个关联函数,因为它没有 self 参数
    // Self 是当前 impl 块中类型的别名,即 Rectangle
    fn square(size: u32) -> Self { 
        Self {
            width: size,
            height: size,
        }
    }
}

关联函数使用 :: 语法调用,而不是 . 语法。

// 调用关联函数
let rect2 = Rectangle::square(20);