Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • 搜索未来:SEO与GEO双引擎实战手册
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • Rust 开发入门
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • 搜索未来:SEO与GEO双引擎实战手册
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • Rust 开发入门
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain

5.5 结构体(struct)与实例化

结构体(struct)是 Rust 中自定义数据类型的一种核心方式,它允许你将多个相关的值组合成一个有意义的整体。可以把结构体想象成一个“蓝图”或“模板”,它定义了数据应该是什么样子的。通过实例化结构体,你可以创建具体的“实例”来存储实际的数据。

5.5.1 定义结构体

在 Rust 中,使用 struct 关键字来定义结构体。结构体的名称通常采用大驼峰命名法(PascalCase)。结构体内部包含多个“字段”(fields),每个字段都有一个名称和类型。

基本语法:

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

在这个例子中,我们定义了一个名为 User 的结构体,它包含四个字段:

  • username: 一个 String 类型的用户名。
  • email: 一个 String 类型的电子邮件地址。
  • sign_in_count: 一个 u64 类型的登录次数。
  • active: 一个 bool 类型的状态,表示用户是否活跃。

5.5.2 创建结构体实例

定义好结构体后,就可以创建它的实例了。创建实例时,需要为所有字段提供具体的值。字段的顺序可以与定义时的顺序不同。

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

注意: 整个实例必须是可变的,Rust 不支持只让结构体的某些字段可变。如果要修改字段的值,需要在实例前加上 mut 关键字。

let mut user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotheruser456"),
    active: false,
    sign_in_count: 0,
};

user2.email = String::from("newemail@example.com"); // 可以修改

5.5.3 访问结构体字段

使用点号(.)来访问结构体实例的字段。

println!("User email: {}", user1.email);
println!("User is active: {}", user1.active);

5.5.4 字段初始化简写

当函数参数名与结构体字段名完全相同时,可以使用字段初始化简写(Field Init Shorthand)来简化代码。

fn build_user(email: String, username: String) -> User {
    User {
        email,    // 等价于 email: email
        username, // 等价于 username: username
        active: true,
        sign_in_count: 1,
    }
}

5.5.5 结构体更新语法

你可以基于一个已有的结构体实例,快速创建一个新的实例,并只修改其中部分字段。这被称为结构体更新语法(Struct Update Syntax),使用 .. 操作符。

let user3 = User {
    email: String::from("third@example.com"),
    username: String::from("thirduser789"),
    ..user1 // 从 user1 中获取 active 和 sign_in_count 字段的值
};

重要提示: 使用 .. 时,如果被复制的字段(如 user1 的 username 和 email)是实现了 Copy trait 的类型(例如整数、布尔值),则 user1 仍然可用。但如果字段是所有权类型(如 String),则 user1 中的 username 和 email 的所有权会被移动到 user3 中,之后 user1 将不再有效(除非你显式地克隆它们)。

5.5.6 元组结构体 (Tuple Structs)

元组结构体是一种特殊形式的结构体,它的字段没有名称,只有类型。它看起来像是一个命名的元组,非常适合用来创建不同类型的新类型(newtype)。

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);

尽管 Color 和 Point 内部都由三个 i32 组成,但它们是不同的类型。你可以通过索引来访问元组结构体的字段。

println!("Red component: {}", black.0);

5.5.7 单元结构体 (Unit-Like Structs)

单元结构体没有任何字段。它们通常用于在某个类型上实现 trait,但不需要存储任何数据。

struct AlwaysEqual;

let subject = AlwaysEqual;

5.5.8 结构体的所有权

结构体的字段可以拥有数据的所有权,也可以持有引用(通过生命周期)。但默认情况下,结构体实例拥有其字段的所有权。当结构体实例被丢弃时,其所有字段也会被丢弃。

struct User {
    username: String, // 拥有 String 的所有权
    // ...
}

5.5.9 打印结构体

结构体默认没有实现 Display trait,因此不能直接用 {} 格式化打印。但你可以通过添加 #[derive(Debug)] 属性来让结构体实现 Debug trait,然后使用 {:?} 或 {:#?} 来打印。

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

fn main() {
    let rect = Rectangle {
        width: 30,
        height: 50,
    };
    println!("rect is {:?}", rect); // 单行打印
    println!("rect is {:#?}", rect); // 多行漂亮打印
}

输出示例:

rect is Rectangle { width: 30, height: 50 }
rect is Rectangle {
    width: 30,
    height: 50,
}

5.5.10 结构体的方法

结构体不仅可以存储数据,还可以通过 impl 块来关联函数(方法)。方法的第一个参数总是 self(或其变体 &self、&mut self),它代表调用该方法的实例。

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

impl 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 main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };

    println!("The area of rect1 is {} square pixels.", rect1.area());
    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
}

5.5.11 关联函数

在 impl 块中,不带 self 参数的函数被称为“关联函数”(associated functions)。它们通常用于创建新实例的构造函数,例如 String::from()。

impl Rectangle {
    fn square(size: u32) -> Rectangle {
        Rectangle {
            width: size,
            height: size,
        }
    }
}

fn main() {
    let sq = Rectangle::square(3); // 使用 :: 语法调用关联函数
}

总结

结构体是 Rust 中组织和封装数据的基石。通过定义结构体、创建实例、使用字段和方法,你可以构建出清晰、可维护且类型安全的程序。掌握结构体的定义、实例化、更新语法以及方法,是深入学习 Rust 的重要一步。

Last Updated:: 5/9/26, 3:13 PM