在 Rust 的基礎 - Reference 中,透過 reference 來存取到了 value。
在 Rust 的基礎- 所有權規則 中,有提到每個 Value 都有一個所有者 (owner)
在 Rust 中把創建一個 reference 的動作稱為借用 (borrowing)
let hello = "hello".to_string(); let hello_ref = &hello; // 借用 hello
為了確保 Reference 的安全,Rust 有一項編譯期檢查機制 "Borrow Checker",其用意是確保兩方面的事情
- 所有者與 Reference 之間
- Reference 與 Reference 之間
要確認的事項是 Rerference 不可以活得比 Owner 久,比如以下 code
let hello = "hello".to_string();
let hello_ref = &hello;
drop(hello);
println!("{}", hello_ref);
我們會得到以下錯誤
let hello = "hello".to_string();
let hello_ref = &hello;
------ borrow of `hello` occurs here
drop(hello);
^^^^^ move out of `hello` occurs here
println!("{}", hello_ref);
-------- borrow later used here
Reference 與 Reference 之間
在說明 Reference 與 Reference 之間,首先先介紹 Mutable Borrowing,在介紹 Mutable Borrowing 前要先介紹什麼是 Mutable
Rust 相比其他常見的程式語言有一個特點,就是所有變數預設都是唯獨的
底下的這段 codelet hello = "hello".to_string(); hello = "world".to_string();會得到編譯錯誤
let hello = "hello".to_string(); hello = "world".to_string(); ^^^^^ cannot assign twice to immutable variable想要編譯成功需要將程式改為
let mut hello = "hello".to_string(); hello = "world".to_string();
這麼作的思路是預設不能改可以避免潛在問題
而 Borrowing 所創建的 reference 預設是無法修改指向的 Value 的
let mut hello = "hello".to_string();
let hello_ref = &hello;
hello_ref.push_str(" world");
會得到編譯錯誤
let mut hello = "hello".to_string();
let hello_ref = &hello;
hello_ref.push_str(" world");
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `hello_ref` is a `&` reference, \
so the data it refers to cannot be borrowed as mutable
想要修正這個錯誤,需要使用 mutable borrow
let mut hello = "hello".to_string();
let hello_ref = &mut hello;
hello_ref.push_str(" world");
知道了什麼叫做 mutable borrowing 後,我們回到 Reference 與 Reference 之間 的情況,Rust 的規則是
- borrowing 與 mutable borrowing 的 reference 不可重疊使用
- 同時間只能有一個 mutable borrwing 的 reference
比如以下 code
let mut hello = "hello".to_string();
let hello_mut_ref = &mut hello;
let hello_ref = &hello;
hello_mut_ref.push_str(" world");
會得到編譯錯誤
let mut hello = "hello".to_string();
let hello_mut_ref = &mut hello;
---------- mutable borrow occurs here
let hello_ref = &hello;
^^^^^^ immutable borrow occurs here
hello_mut_ref.push_str(" world");
-------------------------------- mutable borrow later used here
為什麼需要這種規則,可以看以下的 code
let hello_mut_ref = &mut hello;
let hello_ref = &hello;
for c in hello_ref.chars() {
hello_mut_ref.push_str(" world");
// push_str may makes the iterator from hello_ref.chars() invalid.
print!("{}", c);
}
在這個範例中我們看到 hello_ref 去透過 chars function 取得了 hello 的 iterator,而在取用的途中,可以看到又透過 hello_mut_ref 在往 hello 內去附加字串。這種附加動作有可能會導致記憶體重分配,導致 hello 的 iterator 在途中變成無用的對象。
總結: Rust 的 Borrow Checker- 所有者與 Reference 之間
- Reference 不可以活得比所有者久
- Reference 與 Reference 之間
- mutable borrowing 與 borrowing 不可同時存在
- mutable borrowing 同時只能存在一個
以上規則可以有效防止 Dangling Pointer 的出現
沒有留言:
張貼留言