從這小節開始,其實是持續延續對擁有權的討論,以下有三組程式,由第一組演變至第三組的思考和寫法。
main函式:
fn main() {
let sushi = String::from("Salmon");
let food = eat_meal(sushi);
println!("{}", food);
}
fn eat_meal(mut meal: String) -> String {
meal.push_str(" and Tuna.");
meal
}
main函式:
let sushi = String::from("Salmon");
let food = eat_meal(sushi);
println!("{}", food);
eat_meal 函式:
fn eat_meal(mut meal: String) -> String
meal.push_str(" and Tuna.");
meal
使用回傳值是為了避免值被釋放,但確實會帶來不便,尤其是在需要頻繁操作字串時,需要不斷地返回並賦值。因此我們就繼續測試有沒有更好的方式。
fn main() {
let sushi = String::from("Salmon");
let food = eat_meal(&sushi);
println!("{}", food);
}
fn eat_meal(meal: &String) -> String {
meal.push_str(" and Tuna."); // ❌ 編譯錯誤:不可變參照不能修改內容
meal
}
main函式:
let food = eat_meal(&sushi);
println!("{}", food);
eat_meal 函式:
fn eat_meal(meal: &String) -> String
meal.push_str(" and Tuna."); // 這行會編譯錯誤,因為課程需要而故意寫。
fn main() {
let mut sushi = String::from("Salmon");
eat_meal(&mut sushi);
}
fn eat_meal(meal: &mut String) {
meal.push_str(" and Tuna.");
println!("Meal steps: {}", meal);
}
寫法 | 擁有權 | 可否修改 | 備註 |
---|---|---|---|
meal: String |
✅ 是 | ❌ 否 | 擁有資料,但不可變 |
mut meal: String |
✅ 是 | ✅ 是 | 擁有資料,可修改 |
meal: &String |
❌ 否 | ❌ 否 | 借用資料,唯讀參照 |
meal: &mut String |
❌ 否 | ✅ 是 | 借用資料,可修改參照 |
&mut T
是較理想的方式。Rust 在借用變數時有一條重要規則:
✅ 你可以擁有任意數量的不可變參照(&T)
❌ 但在有可變參照(&mut T)時,不能同時存在任何其它參照(無論是否為可變)
讓我們透過三段程式碼進行比較:
let coffee = String::from("Caramel Macchiato");
let drink = &coffee;
let soft_drink = &coffee;
println!("{} and {}", drink, soft_drink);
drink
與 soft_drink
都是 &coffee
的不可變參照let mut coffee = String::from("Caramel Macchiato");
let drink = &mut coffee;
let soft_drink = &coffee;
println!("{}", soft_drink); // ✅ 實際可編譯
drink
是可變參照,soft_drink
是不可變參照drink
沒有被使用,Rust 編譯器判定它已經失效let mut coffee = String::from("Caramel Macchiato");
let drink = &mut coffee;
println!("{}", drink); // ✅ 先用完 drink
let soft_drink = &coffee;
println!("{}", soft_drink);
drink
已經不再使用,因此允許 soft_drink
的建立類型 | 可同時出現? | 是否可修改原值 | 備註 |
---|---|---|---|
多個不可變參照 &T |
✅ 是 | ❌ 否 | 可重疊借用 |
可變參照 &mut T + &T |
❌ 否 | ✅ 是(僅限 &mut) | 資料競爭風險,不允許 |
先使用完可變再借不可變 | ✅ 是 | ✅ 是 | 編譯器能確認作用域不重疊,允許 |
這些借用規則確保 Rust 在不使用垃圾回收的情況下,依然能達成編譯時的記憶體安全檢查。理解可變與不可變參照的使用邊界,是掌握 Rust 擁有權系統的重要一環。