借用(Borrowing)與參考#
上一章介紹了所有權的移動機制。若每次傳入函數都要移動所有權,程式碼會變得非常繁瑣。
借用(Borrowing) 透過 參考(Reference) 讓我們在不取得所有權的情況下,使用某個值。
1. 參考(Reference)#
參考使用 & 符號建立,讓你「借用」某個值,而不取走它的所有權:
1
2
3
4
5
6
7
8
9
| fn main() {
let s = String::from("hello");
let len = calculate_length(&s); // 借用 s
println!("{s} 的長度是 {len}"); // s 仍有效
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s 在此離開作用域,但因為它沒有所有權,所以不會釋放資料
|
參考預設也是 不可變 的。
2. 可變參考(Mutable Reference)#
若需要透過參考修改資料,使用 &mut:
1
2
3
4
5
6
7
8
9
| fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{s}"); // hello, world
}
fn change(s: &mut String) {
s.push_str(", world");
}
|
3. 可變參考的限制#
同一時間,對同一個值只能有一個可變參考:
1
2
3
4
5
6
| fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
// let r2 = &mut s; // 錯誤!不能同時有兩個可變參考
println!("{r1}");
}
|
這個限制可以在編譯時期防止 資料競爭(data race) 。
4. 不可變與可變參考不能並存#
當有不可變參考存在時,不能同時建立可變參考:
1
2
3
4
5
6
7
| fn main() {
let mut s = String::from("hello");
let r1 = &s; // 不可變參考
let r2 = &s; // 可以有多個不可變參考
// let r3 = &mut s; // 錯誤!已有不可變參考
println!("{r1}, {r2}");
}
|
Rust 的 非詞彙作用域生命週期(NLL) 讓編譯器追蹤參考最後一次使用的位置,不再使用後就允許新參考:
1
2
3
4
5
6
7
8
9
| fn main() {
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{r1}, {r2}"); // r1、r2 最後使用在此
let r3 = &mut s; // 此處 r1、r2 已結束,可以建立可變參考
println!("{r3}");
}
|
5. 懸空參考(Dangling Reference)#
Rust 編譯器保證參考 永遠不會懸空 (指向已釋放的記憶體):
1
2
3
4
| fn dangle() -> &String { // 錯誤!回傳懸空參考
let s = String::from("hello");
&s
} // s 在此被釋放,&s 指向無效記憶體
|
正確做法是回傳值本身(轉移所有權):
1
2
3
4
| fn no_dangle() -> String {
let s = String::from("hello");
s // 所有權移出函數,記憶體不會被釋放
}
|
6. 字串切片(String Slice)#
切片(Slice)是對集合某一部分的參考,型別為 &str:
1
2
3
4
5
6
| fn main() {
let s = String::from("hello world");
let hello = &s[0..5]; // "hello"
let world = &s[6..11]; // "world"
println!("{hello}, {world}");
}
|
字串字面值 "hello" 的型別就是 &str,是指向程式二進位檔中的切片,因此字面值永遠是不可變的。
函數接受字串參數時,慣用 &str 以同時接受 String 和 &str:
1
2
3
4
5
6
7
8
9
| fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
|
Reference#
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html