【Rust自学】5.1. 定义并实例化struct

发布时间:2026/7/23 18:47:32
【Rust自学】5.1. 定义并实例化struct 5.1 定义并实例化struct5.1.1. 什么是structstruct的中文意思为“结构体”。它是一种自定义数据类型允许程序为相关联的值命名并打包形成有意义的组合。它类似于其他编程语言中的“类”或“结构”但它只提供数据存储功能不包含方法。学过 C/C 的人可能对struct这个关键字已经很熟悉但它们有区别- Cstruct是一种用来组织数据的简单聚合类型。它只能包含数据没有方法。Cstruct与class非常相似可以包含数据和方法唯一的语法区别是在struct中默认的访问权限是public在class中默认的访问权限是private。Ruststruct仅用于定义数据结构不包含方法。方法需要通过impl块为结构体定义。Rust 提供了更严格的所有权、生命周期和内存管理机制。5.1.2. 定义struct使用struct关键字用驼峰命名法为整个 struct 命名。在花括号内为所有字段定义名称和类型。例子为 HLTV 上的 CS 职业选手定制存储各项数据的 struct补充信息CS 职业选手的数据一般由Rating、DPR、KAST、Impact、ADR 和 KPR组成。struct Stats{ rating: f32, dpr: f32, kast: f32, impact: f32, adr: f32, kpr: f32, }5.1.3. 实例化struct想要使用struct需要创建它的实例- 为每个字段指定具体值不能少赋字段的值。-无需按声明的顺序进行指定。就以 donk 为例创建他的数据库fn main() { let donk Stats { rating: 1.27, impact: 1.4, dpr: 0.67, adr: 88.8, kast: 74.1, kpr: 0.85, }; }5.1.4. 取得struct里某个字段的值可以使用点标记法取得 struct 里字段的值fn main() { let mut donk Stats { rating: 1.27, impact: 1.4, dpr: 0.67, adr: 88.8, kast: 74.1, kpr: 0.85, }; donk.rating 2.59; }如果要更改 struct 的值记得在实例化时使用可变变量关键字mut。在 struct 中可变性的最小单位就是整个实例不能单独控制单个字段的可变性。一旦 struct 实例被声明为可变的那么这个实例下的所有字段都是可变的。5.1.5. 使用struct作为函数返回值函数里的最后一个表达式就是它的返回值所以使用 struct 作为返回值时只需要确保构建 struct 是这个函数的最后一个表达式不带分号即可fn change_stats(rating: f32, impact:f32, dpr:f32, adr:f32, kast:f32, kpr:f32) - Stats{ Stats { rating: rating, impact: impact, dpr: dpr, adr: adr, kast: kast, kpr: kpr, } }5.1.6. 字段初始化的简写Rust 与 JS 和 C# 一样在某些情况下字段初始化可以简写。当字段名与字段值对应的变量名相同时就可以简写。比如在上一个代码例中所有的字段名都和字段值对应的变量名相同所以可以将其简写为fn change_stats(rating: f32, impact:f32, dpr:f32, adr:f32, kast:f32, kpr:f32) - Stats{ Stats { rating, impact, dpr, adr, kast, kpr, } }当然不只是全部对应才能这么写只要有一个字段符合简写条件就可以在那里使用简写其他的保持正常写法就行。5.1.7. struct的更新语法当你基于某个已有的 struct 实例来创建新实例并且新实例有与旧实例相同的字段时就可以使用更新语法。比如我要创建 sh1ro 的数据他的 rating 是 1.25impact 是 1.2其余与 donk 一样这是基础的写法fn main() { let donk Stats { rating: 1.27, impact: 1.4, dpr: 0.67, adr: 88.8, kast: 74.1, kpr: 0.85, }; let sh1ro Stats { rating: 1.25, impact: 1.2, dpr: donk.dpr, adr: donk.adr, kast: donk.kast, kpr: donk.kpr, }; }这样写比较麻烦所以 Rust 提供了这样的语法糖fn main() { let donk Stats { rating: 1.27, impact: 1.4, dpr: 0.67, adr: 88.8, kast: 74.1, kpr: 0.85, }; let sh1ro Stats { rating: 1.25, impact: 1.2, ..donk }; }只需要写有变化的部分其余部分只需要写..加上另一个 struct 实例的名字即可表示剩下没有赋值的字段的值都与另一个实例对应字段的值相同。5.1.8. 元组结构体Tuple struct元组结构体是一种类似元组的结构体。元组结构体整体有名字但里面的元素没有。适用于想给整个元组起名并让它不同于其他元组而且又不需要给每个元素起名的情况。定义元组结构体时使用struct关键字后边是名字以及里面元素的类型。例子struct Color(u8, u8, u8); struct Point(i32, i32, i32); let black Color(0, 0, 0); let origin Point(0, 0, 0);有的人戏谑地说元组结构体在传统编程语言中没有类似物这是来自Haskell的高贵血统。这是因为在许多传统的面向对象语言如 Java、C中结构体或类是具名且字段命名的而元组则是匿名且仅基于顺序的。没有中间形式来融合两者的优点。Rust 的元组结构体概念与 Haskell 的新类型Newtype Pattern有直接关系在 Haskell 中可以通过newtype来定义类似的模式。需要注意的是即使两个元组结构体有相同数量的元素并且对应元素的数据类型都一样它们也不该被视为相同的类型因为它们是不同的 struct。5.1.9. 类单元结构体Unit-Like Structunit-like struct被称为类单元结构体因为它们的行为类似于单元类型()。当需要类型标记或想要在某种类型上实现 trait可以理解为接口但不想在类型本身中存储任何数据时就会使用它们。这类似于 Go 语言中的空结构体struct{}。struct ReadOnly; struct WriteOnly; fn process_dataT(_mode: T) { // Used only as a type marker } fn main() { process_data(ReadOnly); process_data(WriteOnly); }这个例子实现了类型标记。5.1.10. struct数据的所有权struct User { active: bool, username: String, email: String, sign_in_count: u64, }在这个例子中username和email都使用的是String类型而不是str因为String是自有类型owned type拥有自身全部数据的所有权。在这种情况下只要实例是有效的那么里面的字段数据也肯定是有效的。像str这样的引用类型也可以存放进struct里但这需要生命周期以后讲。简单来说生命周期保证只要struct实例是有效的那么里面的引用也是有效的。如果 struct 里面存储引用而不使用生命周期就会报错missing lifetime specifier。