Rust中的Enum与Struct示例详解
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>结构体struct</li><ul class="second_class_ul"><li>具名结构体(named strcut)</li><ul class="third_class_ul"><li>可见性</li><li>trait(继承/多态)</li><li>泛型与生命周期</li></ul><li>元组结构体(tuple struct)</li><ul class="third_class_ul"></ul><li>单元结构体(unit struct)</li><ul class="third_class_ul"></ul></ul><li>枚举(enum)</li><ul class="second_class_ul"><li>模式匹配</li><ul class="third_class_ul"></ul><li>常见enum</li><ul class="third_class_ul"></ul></ul></ul></div><p>在 Rust 中,<code>struct</code>(结构体)和<code>enum</code>(枚举)是两种核心的自定义类型,分别用于<code>组合相关数据</code>和<code>表示互斥的可能性</code>。</p><p class="maodian"></p><h2>结构体struct</h2>
<p><code>struct</code>用于将多个相关的值组合在一起,形成一个有意义的组</p>
<p class="maodian"></p><h3>具名结构体(named strcut)</h3>
<p>最常用的结构体形式,字段有明确的名称,可读性强,适合数据含义明确的场景。</p>
<ul><li>字段默认私有(仅当前模块内可见)</li><li>通过impl实现关联函数(方法)</li><li>通过<code>..</code>实现赋值(所有未指定的字段,全部替换为…对应变量中的):若字段为移动语义,所有权被移走</li><li>通过trait实现多态(参见《Rust中的特征Trait》)</li></ul>
<div class="jb51code"><pre class="brush:plain;">use std::fmt;
pub struct Person {
pub name: String,
age: u8,
active: bool,
}
impl fmt::Display for Person {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Person {{ name: {}, age: {}, active: {} }}", self.name, self.age, self.active)
}
}
fn main() {
let alice = Person { name: String::from("Alice"), age: 30, active: true };
let mike = Person { name: String::from("Mike"), ..alice };
println!("person: {}", mike);
// 解结构与..
let Person { name, .. } = mike;
println!("name: {}", name);
}</pre></div>
<p class="maodian"></p><h4>可见性</h4>
<p>默认为私有,可通过pub修饰符修改:</p>
<table><thead><tr><th>修饰符</th><th>可见范围</th><th>说明</th></tr></thead><tbody><tr><td><code>pub</code></td><td>全局可见(跨 crate)</td><td>完全公开</td></tr><tr><td><code>pub(crate)</code></td><td>整个当前 crate 内可见</td><td>库内部共享</td></tr><tr><td><code>pub(super)</code></td><td>父模块可见</td><td>子模块辅助函数</td></tr><tr><td><code>pub(in path)</code></td><td>指定模块路径内可见</td><td>最灵活的控制</td></tr><tr><td>(无修饰)</td><td>当前模块私有</td><td>默认私有</td></tr></tbody></table>
<p class="maodian"></p><h4>trait(继承/多态)</h4>
<p>Rust 没有传统 OOP 的类继承(没有基类/子类)。用 trait + impl 来实现接口/多态。</p>
<p>trait定义方法签名集合,实现trait的类必须提供所有对应方法:</p>
<ul><li>静态分发(<code>T: Trait</code>)在编译期确定具体类型(单态化,性能好)。</li><li>动态分发(<code>&dyn Trait</code> 或 <code>Box<dyn Trait></code>)通过虚函数表(vtable),在运行时分发(适合异构集合/插件式架构)。</li></ul>
<div class="jb51code"><pre class="brush:plain;">trait Drawable {
fn draw(&self);
}
struct Circle { radius: f64 }
struct Square { side: f64 }
impl Drawable for Circle {
fn draw(&self) { println!("circle r={}", self.radius); }
}
impl Drawable for Square {
fn draw(&self) { println!("square s={}", self.side); }
}
// 静态分发(泛型)
fn draw_all<T: Drawable>(items: &) {
for item in items { item.draw(); }
}
// 动态分发(trait object)
fn draw_box(items: &) {
for item in items { item.draw(); }
}</pre></div>
<p class="maodian"></p><h4>泛型与生命周期</h4>
<p>结构体可以是泛型的(参见《Rust中的泛型Generics》),也可以带生命周期参数。</p>
<div class="jb51code"><pre class="brush:plain;">struct Holder<'a, T> { r: &'a T, val: T }
struct Pair<T, U>(T, U);</pre></div>
<p>泛型说明:</p>
<table><thead><tr><th>特性</th><th>说明</th></tr></thead><tbody><tr><td><code>struct Point<T></code></td><td>定义泛型结构体</td></tr><tr><td><code>impl<T> Point<T></code></td><td>为所有类型实现方法</td></tr><tr><td><code>impl Point<i32></code></td><td>为特定类型实现方法</td></tr><tr><td><code>T: Display</code></td><td>泛型约束,要求类型实现<code>Display</code>trait</td></tr><tr><td><code>where T: Clone, U: Debug</code></td><td>泛型约束,更清晰的约束语法</td></tr></tbody></table>
<p class="maodian"></p><h3>元组结构体(tuple struct)</h3>
<p>字段没有名称,仅通过位置区分,适合数据结构简单、字段含义可通过位置推断的场景。</p>
<div class="jb51code"><pre class="brush:plain;">// 元组结构体:通过位置区分(x, y)
struct Point(i32, i32);
// 创建实例
let p1 = Point(3, 4);
// 访问字段(通过索引)
println!("x坐标:{}", p1.0);// 输出:x坐标:3</pre></div>
<p class="maodian"></p><h3>单元结构体(unit struct)</h3>
<p>一种不包含任何字段的结构体。它的定义形式类似于一个“空”的结构体:</p>
<ul><li>在内存中不占用任何空间(<code>size_of::<UnitStruct>() == 0</code>)</li><li>主要用于标记类型(表示 “存在性” 而非 “数据”)</li></ul>
<div class="jb51code"><pre class="brush:plain;">// 定义状态
pub struct Locked;
pub struct Unlocked;
// 门的结构,使用泛型参数表示状态
pub struct Door<TState> {
id: u32,
_state: std::marker::PhantomData<TState>,
}
// 只有 Locked 状态才能解锁
impl Door<Locked> {
fn unlock(self) -> Door<Unlocked> {
println!("门 {} 已解锁", self.id);
Door {
id: self.id,
_state: std::marker::PhantomData,
}
}
}
// 只有 Unlocked 状态才能打开
impl Door<Unlocked> {
fn open(&self) {
println!("门 {} 打开", self.id);
}
fn lock(self) -> Door<Locked> {
println!("门 {} 已上锁", self.id);
Door {
id: self.id,
_state: std::marker::PhantomData,
}
}
}
pub fn test_door() {
let door = Door::<Locked> {
id: 101,
_state: std::marker::PhantomData,
};
let door = door.unlock(); // 状态转换
door.open(); // Unlocked 状态可以打开
let door = door.lock(); // 重新上锁
}</pre></div>
<p class="maodian"></p><h2>枚举(enum)</h2>
<p>枚举的核心作用是定义一个类型,其值是有限的、互斥的几种可能变体(variants)之一。每个变体可以关联不同类型和数量的数据。</p>
<p>枚举通过<code>enum</code>关键字定义,每个变体可以是 “空” 的,也可以携带数据(类似元组或结构体)。</p>
<div class="jb51code"><pre class="brush:plain;">// 定义枚举:消息类型
enum Message {
Quit,// 无数据:退出消息
Move { x: i32, y: i32 },// 具名数据:移动到(x,y)
Write(String),// 元组数据:写入文本
ChangeColor(i32, i32, i32),// 元组数据:修改颜色(RGB)
}
// 创建枚举实例
let msg1 = Message::Quit;// 退出消息
let msg2 = Message::Move { x: 10, y: 20 };// 移动到(10,20)
let msg3 = Message::Write(String::from("hello"));// 写入"hello"</pre></div>
<p class="maodian"></p><h3>模式匹配</h3>
<p>枚举的核心用法是通过<code>match</code>表达式匹配其变体,从而处理不同情况(类似 “多分支条件判断”,但更安全)。</p>
<div class="jb51code"><pre class="brush:plain;">fn process_message(msg: Message) {
match msg {
Message::Quit => println!("收到退出消息"),
Message::Move { x, y } => println!("移动到坐标:({}, {})", x, y),
Message::Write(text) => println!("写入内容:{}", text),
Message::ChangeColor(r, g, b) => println!("修改颜色为 RGB({}, {}, {})", r, g, b),
}
}
process_message(msg2);// 输出:移动到坐标:(10, 20)
process_message(msg3);// 输出:写入内容:hello</pre></div>
<p class="maodian"></p><h3>常见enum</h3>
<p><code>Option<T></code>是 Rust 中用于表示 “有值” 或 “无值” 的枚举,彻底避免了空指针(Null)问题。</p>
<div class="jb51code"><pre class="brush:plain;">enum Option<T> {
Some(T),// 有值:存储类型为T的值
None, // 无值
}
</pre></div>
<p><code>Result<T, E></code>用于表示操作 “成功” 或 “失败” 的结果,是 Rust 错误处理的核心类型。</p>
<div class="jb51code"><pre class="brush:plain;">enum Result<T, E> {
Ok(T), // 成功:存储类型为T的结果
Err(E),// 失败:存储类型为E的错误信息
}
</pre></div>
<p><code>Ordering</code>用于表示两个值的比较结果(小于、等于、大于)</p>
<div class="jb51code"><pre class="brush:plain;">enum Ordering {
Less, // 小于
Equal, // 等于
Greater, // 大于
}
</pre></div>
<p>到此这篇关于Rust中的Enum与Struct示例详解的文章就介绍到这了,更多相关Rust Enum与Struct内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li>在Rust中要用Struct和Enum组织数据的原因解析</li><li>Rust中用enum实现多参数Hook机制完整代码</li><li>Rust中non_exhaustive的enum使用确保程序健壮性</li><li>Rust数据类型之结构体Struct的使用</li><li>Rust Struct结构体详解</li><li>解析Rust struct 中的生命周期</li><li>解析rust中的struct</li></ul>
</div>
</div>
<!--endmain--> 好详细的Rust教程!收藏了[:biggrin:]
一直想系统学习Rust的结构体和枚举,今天终于看到这么完整的整理。几个让我印象深刻的点:
**关于结构体**
- 单元结构体的用法之前真没想到能用类型系统来做状态标记,这个Door的例子太生动了[:good:]
- 可见性修饰符讲得很清楚,pub(crate)和pub(super)在写库的时候特别有用
**关于枚举**
- match模式匹配确实是Rust的精髓,比其他语言的switch强大太多
- Option和Result彻底解决空指针问题,这个设计理念很棒
[:question:]想请教一下,单元结构体在项目中实际应用多吗?除了做状态标记,还有什么好玩的用法?
另外关于trait对象那部分,静态分发和动态分发的选择有什么建议吗?性能差异有多大[:疑问:]
再次感谢楼主的分享,期待更多Rust系列教程![:handshake]
頁:
[1]