2.3 結構與列舉#
自訂型別:struct 與 enum#
Rust 的自訂型別只有兩種骨架:struct(結構) 組合多個資料,enum(列舉) 表達「可能是其中一種」。搭配模式匹配(match),它們能表達大多數的資料模型。
struct:組合資料#
struct User {
name: String,
age: u32,
active: bool,
}
fn main() {
// 建立實例
let u = User {
name: String::from("小美"),
age: 25,
active: true,
};
// 存取欄位
println!("{}", u.name);
// 「欄位初始化簡寫」:變數名與欄位名相同時
let name = String::from("阿明");
let age = 30;
let u2 = User { name, age, active: false };
// struct 更新語法:以另一個實例為基底
let u3 = User { active: true, ..u2 };
}
方法(method):impl 區塊#
struct Rectangle {
width: f64,
height: f64,
}
impl Rectangle {
// 關聯函式(沒有 self):像靜態方法,慣用作為建構子
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
// 方法(&self:借用自己,唯讀)
fn area(&self) -> f64 {
self.width * self.height
}
// 可變方法(&mut self)
fn scale(&mut self, factor: f64) {
self.width *= factor;
self.height *= factor;
}
}
fn main() {
let mut r = Rectangle::new(3.0, 4.0);
println!("{}", r.area()); // 12
r.scale(2.0);
println!("{}", r.area()); // 24
}
三種 self 的區別(對應第三章的借用規則):
&self:唯讀借用(最常見)&mut self:可變借用(要改欄位時)self:拿走所有權(少用,如轉換成別的型別)
enum:可能是其中一種#
enum Shape {
Circle(f64), // 帶資料的變體
Rectangle { w: f64, h: f64 }, // 帶命名欄位的變體
Point, // 不帶資料的變體
}
fn area(s: &Shape) -> f64 {
match s {
Shape::Circle(r) => 3.14159 * r * r,
Shape::Rectangle { w, h } => w * h,
Shape::Point => 0.0,
}
}
每個變體可以帶不同的資料——這是 Rust enum 比 C 的 enum 強大之處:它表達的是「這個值是這幾種情況之一,每種情況帶各自的資料」。
標準庫最重要的兩個 enum:Option 與 Result#
複習 1.2 節,它們就是 enum:
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
match:窮盡性檢查#
match 要求覆蓋所有情況——漏掉任何一個變體,編譯錯誤:
fn describe(n: Option<u32>) -> String {
match n {
Some(0) => String::from("零"),
Some(x) if x > 100 => format!("很大:{}", x), // guard 條件
Some(x) => format!("有值:{}", x),
// None => ... ← 不寫這行,編譯錯誤:漏了 None
}
}
窮盡性是工程上的珍寶:未來加了一個新變體,所有漏處理的 match 會在編譯期全部被抓出來。
常用簡寫:if let#
只想處理一種情況時,if let 比 match 簡潔:
if let Some(name) = maybe_name {
println!("有值:{}", name);
} // None 的情況靜默忽略(要處理就用 match)
本章小結#
- struct 組合資料,enum 表達「其中一種」,兩者構成 Rust 的資料模型
- 方法寫在
impl區塊,三種 self:&self唯讀、&mut self可變、self拿走 - enum 變體可帶資料;Option 與 Result 就是 enum
- match 窮盡性檢查:漏情況編譯不過,新增變體時全部受影響處被抓出
- 只處理一種情況用
if let
想一想#
- enum「每個變體帶不同資料」比 C 的 enum 強在哪裡?舉一個你專案中的例子。
- 窮盡性檢查對「未來新增功能」有什麼保護作用?
- 三種 self 各對應第三章的哪種借用?為什麼
&self最常見?