🦀 函式參數與擁有權(Function Parameters and Ownership)
Rust 的所有權機制不只在變數之間賦值時會生效,傳遞參數給函式時也會觸發「所有權轉移(ownership move)」或「複製(copy)」。此外,函式的回傳值也會牽涉所有權的轉移。以下透過四個例子分別說明:Copy 型別、非 Copy 型別、使用 mut
修改參數,以及回傳值的擁有權轉移。
✅ 範例一:Copy 型別(如 i32
)
fn main() {
let x = 5;
makes_copy(x);
println!("{}", x); // ✅ 可以繼續使用 x,因為 i32 是 Copy 型別
}
fn makes_copy(some_integer: i32) {
println!("{}", some_integer);
}
🔍 說明:
-
x
是 i32
,屬於 Copy 型別。
- 呼叫
makes_copy(x)
時,傳遞的是複製值,不是移轉所有權。
- 因此
x
在函式呼叫後仍然可以使用。
📘 Copy 型別特性整理
型別 |
是否 Copy |
傳入函式時會怎樣 |
i32 |
✅ 是 |
複製一份值 |
bool |
✅ 是 |
複製一份值 |
char |
✅ 是 |
複製一份值 |
f64 |
✅ 是 |
複製一份值 |
❌ 範例二:非 Copy 型別(如 String
)
fn main() {
let oranges = String::from("Oranges");
print_my_value(oranges);
println!("{}", oranges); // ❌ 錯誤:所有權已移轉給函式
}
fn print_my_value(value: String) {
println!("{}", value);
}
🔍 說明:
-
String
是堆積型別,不實作 Copy trait。
- 當傳入函式
print_my_value(oranges)
,會觸發 所有權轉移(move)。
- 在函式內部
value
成為新擁有者。
-
main()
裡的 oranges
在那之後不能再使用,否則會編譯錯誤。
📘 非 Copy 型別行為整理
型別 |
是否 Copy |
傳入函式時會怎樣 |
String |
❌ 否 |
移轉所有權 |
Vec<T> |
❌ 否 |
移轉所有權 |
Box<T> |
❌ 否 |
移轉所有權 |
🔧 範例三:使用 mut
修改函式內部參數
fn main() {
let burger = String::from("Burger");
add_fries(burger); // 所有權移轉到函式中
}
fn add_fries(mut meal: String) {
meal.push_str(" and Fires");
println!("{}", meal);
}
🔍 說明:
-
burger
是 String
,非 Copy 型別,傳入函式時發生 所有權轉移。
-
mut meal
表示在函式內部,這個參數是可變的,可修改字串內容。
- 雖然參數可變,但仍然不是原本變數可變,而是所有權已轉移後的新變數。
- 函式結束後
meal
被 drop,burger
也因此失效,無法再使用。
📘 可變參數與所有權關係
特性項目 |
說明 |
mut 參數 |
表示函式內部的參數可以改變(僅限內部使用) |
所有權轉移 |
呼叫時會發生 move,原變數將無法再使用 |
修改後不回傳值 |
若希望修改完還能使用原變數,需搭配 &mut 參照方式處理 |
🔁 範例四:回傳值會移轉所有權
fn main() {
let cake = bake_cake();
println!("I now have a {} cake.", cake);
}
fn bake_cake() -> String {
let cake_name = String::from("Chocolate Mousse");
cake_name // 可簡寫為:String::from("Chocolate Mousse")
}
🔍 說明:
- 函式
bake_cake()
內部建立一個 String
。
- 回傳這個變數會導致其所有權被移轉到呼叫者(main 的 cake)。
- 因此
cake
變數現在擁有回傳的字串,可以安全使用。
- 這也是 Rust 在沒有垃圾回收下,安全移動資料的方式之一。
📘 回傳值與所有權關係
行為項目 |
說明 |
回傳 Copy 型別 |
值被複製(如 i32) |
回傳非 Copy 型別 |
所有權被移轉(如 String、Vec) |
可簡寫函式 |
如果回傳的是表達式,最後一行可省略 return 與分號 |
✅ 小結
類型分類 |
是否移轉所有權 |
可否修改 |
備註 |
Copy 型別 |
❌ 否(會複製) |
✅ 可以修改副本 |
呼叫函式後變數仍可使用 |
非 Copy 型別 |
✅ 是 |
✅ 可變(需 mut ) |
呼叫函式後變數失效,除非用借用或 clone |
回傳值 |
✅ 是(非 Copy) |
✅ 可用 |
回傳即表示所有權移交 |
Rust 強迫我們思考變數的擁有權,在函式參數與回傳值中尤其重要。若希望保留變數又要傳入函式,可以改用 &value
借用參照,或使用 .clone()
複製堆積資料。