結構體與方法
結構體(struct)把多個相關的欄位組成一個自訂型別。搭配 impl 區塊,可以替這個型別加上方法。Rust 沒有 class,struct 加 impl 就是最常見的物件式寫法。
定義與建立
struct User {
name: String,
email: String,
age: u32,
active: bool,
}
fn main() {
let mut user = User {
name: String::from("小明"),
email: String::from("ming@example.com"),
age: 30,
active: true,
};
user.age += 1; // 要修改欄位,整個實例必須是 mut
println!("{} {} {}", user.name, user.email, user.age);
}
Rust 不允許只把單一欄位標為可變,整個實例要嘛可變,要嘛不可變。
欄位簡寫與更新語法
變數名稱與欄位名稱相同時可以簡寫;..other 則能沿用另一個實例的其餘欄位:
struct User {
name: String,
email: String,
active: bool,
}
fn build_user(name: String, email: String) -> User {
User { name, email, active: true } // 欄位簡寫
}
fn main() {
let u1 = build_user(String::from("小明"), String::from("a@example.com"));
let u2 = User {
email: String::from("b@example.com"),
..u1 // 其餘欄位取自 u1
};
println!("{} {}", u2.name, u2.email);
}
注意:..u1 會把 u1 裡沒有被 Copy 的欄位(這裡是 name)移動過來,之後 u1 就不能整個使用了。
其他形式
struct Color(u8, u8, u8); // tuple struct:欄位沒有名稱
struct Marker; // unit struct:沒有任何欄位
fn main() {
let red = Color(255, 0, 0);
println!("{} {} {}", red.0, red.1, red.2);
let _m = Marker;
}
用 derive 輸出除錯資訊
想用 {:?} 印出自訂型別,需要加上 #[derive(Debug)],編譯器會自動產生實作。{:#?} 則以較易讀的多行格式輸出:
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 3, y: 4 };
println!("{:?}", p);
println!("{:#?}", p);
}
方法與關聯函式
用 impl 區塊為型別定義函式。第一個參數是 self 的稱為方法(method),沒有的稱為關聯函式(associated function):
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 關聯函式:用 Rectangle::new(...) 呼叫,常當作建構函式
fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
// 方法:唯讀借用 self
fn area(&self) -> u32 {
self.width * self.height
}
// 方法:需要修改時使用 &mut self
fn scale(&mut self, factor: u32) {
self.width *= factor;
self.height *= factor;
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() {
let mut rect = Rectangle::new(30, 50);
println!("面積 {}", rect.area());
rect.scale(2);
println!("{:?}", rect);
let small = Rectangle::new(10, 20);
println!("放得下嗎? {}", rect.can_hold(&small));
}
self 的三種寫法,對應前面學過的所有權規則:
| 寫法 | 意義 | 使用時機 |
|---|---|---|
&self |
唯讀借用 | 最常見,只讀取資料 |
&mut self |
可修改借用 | 需要修改欄位 |
self |
取走所有權 | 把實例轉換成別的東西,之後不能再用 |
Self 是 impl 目標型別的別名,寫成 Self 比重複型別名稱方便,也更好維護。
推薦影音
結構體
簡述:微軟《Beginner's Series to Rust》第 15 集,介紹 struct 的定義與使用。
結構體與方法語法
簡述:Let's Get Rusty 依照官方書籍第 5 章製作,涵蓋 struct、方法與關聯函式,對應本頁的「方法與關聯函式」。
下一頁:列舉與模式比對。