ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Comprehensive Rust 教程:深入理解 Rust 具名结构体(Named Structs)的定义、初始化与更新

Comprehensive Rust 教程:深入理解 Rust 具名结构体(Named Structs)的定义、初始化与更新 Comprehensive Rust 教程深入理解 Rust 具名结构体Named Structs的定义、初始化与更新【免费下载链接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.项目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust导读本篇文章以 Google Android 团队使用的开源 Rust 课程comprehensive-rust中 named-structs.md 一节为骨架系统讲解 Rust 具名结构体Named Structs的完整知识体系从最基本的定义与实例化、字段读写与初始化简写到零尺寸结构体、Default派生、结构体更新语法struct update syntax等进阶话题。读完本文你将掌握在真实项目中定义与使用具名结构体的全部实践细节并能将其与元组结构体、枚举等 Rust 用户自定义类型正确区分、灵活组合。什么是具名结构体与 C 和 C 类似Rust 支持自定义结构体struct。所谓“具名结构体”Named Struct是指结构体的每个字段都有名字。课程 named-structs.md 给出了一个最小而完整的示例struct Person { name: String, age: u8, } fn describe(person: Person) { println!({} is {} years old, person.name, person.age); } fn main() { let mut peter Person { name: String::from(Peter), age: 27, }; describe(peter); peter.age 28; describe(peter); let name String::from(Avery); let age 39; let avery Person { name, age }; describe(avery); }这段代码集中展示了具名结构体的三个核心能力定义类型用struct关键字声明字段name: String、age: u8字段类型可以是标准库类型也可以是自定义类型创建实例用结构体名加花括号字面量Person { name: ..., age: ... }构造值读写字段通过点号语法person.name读取通过peter.age 28修改需要实例本身是mut可变绑定。与 C / C 的对比课程讲师在“Key Points”中强调了三层对比这也是具名结构体最容易与其它语言混淆的地方不需要typedef与 C 一致、与 C 不同struct Person定义出的Person本身就是类型名可以直接使用无需typedef struct Person Person;之类的样板代码没有继承与 C 不同Rust 结构体之间不存在继承关系。类型间的共性行为通过 trait特征实现例如后文会提到的Default、Debug等组合优于继承字段没有默认值结构体字段不支持在声明处指定默认值。若需要“默认构造”必须显式实现或派生标准库的Defaulttrait这一点后面会详细展开。字段初始化简写Field Init Shorthand课程示例中的avery构造展示了初始化简写let name String::from(Avery); let age 39; let avery Person { name, age };当局部变量名与字段名完全一致时name: name可以简写为name。这在构造大量字段的结构体例如从函数参数或其它变量组装领域对象时能显著减少重复。从源码风格看named-structs.md 特意把两种写法并列展示正是为了让学员直观对比完整写法与简写法的差异。结构体更新语法Struct Update Syntax当新结构体的大部分字段值来自已有实例时Rust 提供了更新语法..。课程原文给出如下示例let jackie Person { name: String::from(Jackie), ..avery };语义要点..avery会把avery中未被显式指定的其余字段此处即age的值拷贝/移动过来不必逐个字段手写..avery必须作为最后一个元素出现其后不能再跟其它字段赋值它常用于与Default配合的“部分初始化”先取一个全默认值再覆盖少数关键字段见下文。与 Default trait 的组合使用因为具名结构体字段本身没有默认值Rust 社区的标准做法是实现Defaulttrait。课程 std-traits/default.md 给出了同时使用派生与更新语法的完整示例#[derive(Debug, Default)] struct Derived { x: u32, y: String, z: Implemented, } #[derive(Debug)] struct Implemented(String); impl Default for Implemented { fn default() - Self { Self(John Smith.into()) } } fn main() { let default_struct Derived::default(); dbg!(default_struct); let almost_default_struct Derived { y: Y is set!.into(), ..Derived::default() }; dbg!(almost_default_struct); let nothing: OptionDerived None; dbg!(nothing.unwrap_or_default()); }从中可以得到几条可直接落地的实践结论#[derive(Default)]要求所有字段类型都实现Default派生实现会把每个字段设为各自类型的默认值标准库常见类型普遍实现了合理的Default如数字为0、String为空串..Derived::default()这种“先默认、后覆盖”的模式正是更新语法最主要的应用场景标准库还提供Option::unwrap_or_default等便捷方法底层都依赖类型的Default实现。具名结构体的其它形态零尺寸结构体与相邻类型课程把具名结构体放在“User-Defined Types”模块的开头紧接着是元组结构体Tuple Structs与枚举Enums。理解这一序列有助于把握具名结构体在 Rust 类型体系中的位置。零尺寸结构体Zero-Sized Struct当结构体没有任何字段时可以写成struct Foo;这是零尺寸类型ZST的一种形式。它的用途是在“只需要挂载行为、不需要存储数据”的场景例如为某个类型实现 trait 但没有需要保存在值里的数据时。ZST 只有唯一一个值即类型本身的名字。元组结构体与 newtype 的区别若字段名不重要可以用元组结构体struct Point(i32, i32);通过p.0、p.1按下标访问见 tuple-structs.md。单字段元组结构体常被用作 newtype例如课程中的struct PoundsOfForce(f64); struct Newtons(f64);newtype 与具名结构体的核心差别在于newtype 包裹的类型与原类型不可互换编译器会阻止把PoundsOfForce直接传给期望Newtons的函数从而把“单位”、“已验证”等信息编码进类型系统。课程 idiomatic/leveraging-the-type-system/newtype-pattern.md 用pub struct UserId(u64);进一步说明newtype 不会自动继承底层类型的方法和运算符需要刻意转发。这与类型别名形成鲜明对比——aliases.md 指出type InventoryCount usize只是别名、与原类型可互换因此“能用 newtype 就别用别名”。与枚举的关系具名结构体可以放进枚举的变体里构成“结构体变体”。课程 enums.md 中的例子enum PlayerMove { Pass, // 简单变体 Run(Direction), // 元组变体 Teleport { x: u32, y: u32 }, // 结构体变体 }这提示了一个建模思路当一组形态互斥同一时刻只能取其一时用枚举当形态固定、字段齐全时用具名结构体二者可以嵌套使用。为具名结构体补充行为方法与接收者具名结构体本身只定义数据行为通过impl块关联。课程 methods-and-traits/methods.md 给出了具名结构体加方法的完整模式impl CarRace { fn new(name: str) - Self { Self { name: String::from(name), laps: Vec::new() } } // 无接收者静态方法 fn add_lap(mut self, lap: i32) { self.laps.push(lap); } // mut self fn print_laps(self) { ... } // self fn finish(self) { ... } // self所有权 }与具名结构体配套的接收者语法归纳如下接收者语义调用后实例可用性无接收者静态方法常作为构造函数惯例命名为new—self共享不可变借用可继续使用mut self唯一可变借用可继续使用self取得所有权移动不可再用除非所有权被转移mut self取得所有权且可修改不可再用综合实战用结构体与枚举建模电梯事件课程在模块末尾安排了 Elevator Events 练习其目标是用用户自定义类型表达一个电梯控制系统中“控制器需要响应的事件”并在 exercise.rs 中给出了完整参考实现。虽然该练习主体是枚举但它清晰地展示了具名结构体思想在真实建模中的延伸#[derive(Debug)] enum Event { ButtonPressed(Button), CarArrived(Floor), CarDoorOpened, CarDoorClosed, } type Floor i32; #[derive(Debug)] enum Direction { Up, Down } #[derive(Debug)] enum Button { LobbyCall(Direction, Floor), CarFloor(Floor), }从仓库中的 solution.md 可以提炼出该练习想传达的四个要点带数据的枚举变体CarArrived(Floor)携带整数、ButtonPressed(Button)携带嵌套枚举让Event能用类型安全的方式表达丰富状态类型别名type Floor i32只是给i32一个语义化名字编译器眼中仍是i32#[derive(Debug)]自动生成格式化代码使{:?}可直接打印不派生就得手写fmt::Debug嵌套枚举Button作为独立枚举嵌套在Event::ButtonPressed中这种层级结构在 Rust 中常用于表达复杂领域。其中#[derive(Debug)]同样适用于具名结构体——课程中Person、Derived等例子都能通过派生Debug获得开箱即用的调试输出。练习文件 exercise.rs 顶部的#![allow(dead_code)]也值得注意当类型只被打印、未被真正“使用”时编译器会误判其为死代码该属性用于消除这类误报。关键结论速查围绕具名结构体本文全部关键结论汇总如下每一条均可回溯到仓库中的对应文档具名结构体用struct Name { field: Type, ... }定义无需typedef没有继承named-structs.md字段无默认值默认构造依赖Defaulttrait可通过#[derive(Default)]派生std-traits/default.md初始化简写Person { name, age }在变量名与字段名一致时可用named-structs.md更新语法..avery必须位于构造字面量的最后一位常用于“先Default再覆盖”的局部初始化named-structs.md、std-traits/default.mdstruct Foo;是零尺寸结构体适合只承载行为、不存数据的类型named-structs.md字段名不重要时改用元组结构体单字段元组结构体即 newtype可与原类型严格区分tuple-structs.md、newtype-pattern.md具名结构体的数据形态固定枚举表达互斥形态两者可嵌套组合建模复杂领域enums.md、exercise.rs行为通过impl块与方法接收者self/self/mut self关联到结构体methods.md。掌握了这些要点你就能在综合 Rust 项目中准确地定义数据模型、安全地组织初始化逻辑并自然过渡到 trait、借用检查与领域建模等更高级话题。【免费下载链接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.项目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表