W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
ch15-03-drop.md
commit d44317c3122b44fb713aba66cc295dee3453b24b
對于智能指針模式來說第二個重要的 trait 是 Drop
,其允許我們在值要離開作用域時執(zhí)行一些代碼??梢詾槿魏晤愋吞峁?nbsp;Drop
trait 的實現(xiàn),同時所指定的代碼被用于釋放類似于文件或網(wǎng)絡(luò)連接的資源。我們在智能指針上下文中討論 Drop
是因為其功能幾乎總是用于實現(xiàn)智能指針。例如,當(dāng) Box<T>
被丟棄時會釋放 box 指向的堆空間。
在其他一些語言中,我們不得不記住在每次使用完智能指針實例后調(diào)用清理內(nèi)存或資源的代碼。如果忘記的話,運行代碼的系統(tǒng)可能會因為負荷過重而崩潰。在 Rust 中,可以指定每當(dāng)值離開作用域時被執(zhí)行的代碼,編譯器會自動插入這些代碼。于是我們就不需要在程序中到處編寫在實例結(jié)束時清理這些變量的代碼 —— 而且還不會泄漏資源。
指定在值離開作用域時應(yīng)該執(zhí)行的代碼的方式是實現(xiàn) Drop
trait。Drop
trait 要求實現(xiàn)一個叫做 drop
的方法,它獲取一個 self
的可變引用。為了能夠看出 Rust 何時調(diào)用 drop
,讓我們暫時使用 println!
語句實現(xiàn) drop
。
示例 15-14 展示了唯一定制功能就是當(dāng)其實例離開作用域時,打印出 Dropping CustomSmartPointer!
的結(jié)構(gòu)體 CustomSmartPointer
。這會演示 Rust 何時運行 drop
函數(shù):
文件名: src/main.rs
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
}
示例 15-14:結(jié)構(gòu)體 CustomSmartPointer
,其實現(xiàn)了放置清理代碼的 Drop
trait
Drop
trait 包含在 prelude 中,所以無需導(dǎo)入它。我們在 CustomSmartPointer
上實現(xiàn)了 Drop
trait,并提供了一個調(diào)用 println!
的 drop
方法實現(xiàn)。drop
函數(shù)體是放置任何當(dāng)類型實例離開作用域時期望運行的邏輯的地方。這里選擇打印一些文本以展示 Rust 何時調(diào)用 drop
。
在 main
中,我們新建了兩個 CustomSmartPointer
實例并打印出了 CustomSmartPointer created.
。在 main
的結(jié)尾,CustomSmartPointer
的實例會離開作用域,而 Rust 會調(diào)用放置于 drop
方法中的代碼,打印出最后的信息。注意無需顯式調(diào)用 drop
方法:
當(dāng)運行這個程序,會出現(xiàn)如下輸出:
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished dev [unoptimized + debuginfo] target(s) in 0.60s
Running `target/debug/drop-example`
CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!
當(dāng)實例離開作用域 Rust 會自動調(diào)用 drop
,并調(diào)用我們指定的代碼。變量以被創(chuàng)建時相反的順序被丟棄,所以 d
在 c
之前被丟棄。這個例子剛好給了我們一個 drop 方法如何工作的可視化指導(dǎo),不過通常需要指定類型所需執(zhí)行的清理代碼而不是打印信息。
不幸的是,我們并不能直截了當(dāng)?shù)慕?nbsp;drop
這個功能。通常也不需要禁用 drop
;整個 Drop
trait 存在的意義在于其是自動處理的。然而,有時你可能需要提早清理某個值。一個例子是當(dāng)使用智能指針管理鎖時;你可能希望強制運行 drop
方法來釋放鎖以便作用域中的其他代碼可以獲取鎖。Rust 并不允許我們主動調(diào)用 Drop
trait 的 drop
方法;當(dāng)我們希望在作用域結(jié)束之前就強制釋放變量的話,我們應(yīng)該使用的是由標(biāo)準庫提供的 std::mem::drop
。
如果我們像是示例 15-14 那樣嘗試調(diào)用 Drop
trait 的 drop
方法,就會得到像示例 15-15 那樣的編譯錯誤:
文件名: src/main.rs
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
c.drop();
println!("CustomSmartPointer dropped before the end of main.");
}
示例 15-15:嘗試手動調(diào)用 Drop
trait 的 drop
方法提早清理
如果嘗試編譯代碼會得到如下錯誤:
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
error[E0040]: explicit use of destructor method
--> src/main.rs:16:7
|
16 | c.drop();
| --^^^^--
| | |
| | explicit destructor calls not allowed
| help: consider using `drop` function: `drop(c)`
For more information about this error, try `rustc --explain E0040`.
error: could not compile `drop-example` due to previous error
錯誤信息表明不允許顯式調(diào)用 drop
。錯誤信息使用了術(shù)語 析構(gòu)函數(shù)(destructor),這是一個清理實例的函數(shù)的通用編程概念。析構(gòu)函數(shù) 對應(yīng)創(chuàng)建實例的 構(gòu)造函數(shù)。Rust 中的 drop
函數(shù)就是這么一個析構(gòu)函數(shù)。
Rust 不允許我們顯式調(diào)用 drop
因為 Rust 仍然會在 main
的結(jié)尾對值自動調(diào)用 drop
,這會導(dǎo)致一個 double free 錯誤,因為 Rust 會嘗試清理相同的值兩次。
因為不能禁用當(dāng)值離開作用域時自動插入的 drop
,并且不能顯式調(diào)用 drop
,如果我們需要強制提早清理值,可以使用 std::mem::drop
函數(shù)。
std::mem::drop
函數(shù)不同于 Drop
trait 中的 drop
方法??梢酝ㄟ^傳遞希望提早強制丟棄的值作為參數(shù)。std::mem::drop
位于 prelude,所以我們可以修改示例 15-15 中的 main
來調(diào)用 drop
函數(shù)。如示例 15-16 所示:
文件名: src/main.rs
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
drop(c);
println!("CustomSmartPointer dropped before the end of main.");
}
示例 15-16: 在值離開作用域之前調(diào)用 std::mem::drop
顯式清理
運行這段代碼會打印出如下:
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished dev [unoptimized + debuginfo] target(s) in 0.73s
Running `target/debug/drop-example`
CustomSmartPointer created.
Dropping CustomSmartPointer with data `some data`!
CustomSmartPointer dropped before the end of main.
Dropping CustomSmartPointer with data `some data`!
出現(xiàn)在 CustomSmartPointer created.
和 CustomSmartPointer dropped before the end of main.
之間,表明了 drop
方法被調(diào)用了并在此丟棄了 c
。
Drop
trait 實現(xiàn)中指定的代碼可以用于許多方面,來使得清理變得方便和安全:比如可以用其創(chuàng)建我們自己的內(nèi)存分配器!通過 Drop
trait 和 Rust 所有權(quán)系統(tǒng),你無需擔(dān)心之后的代碼清理,Rust 會自動考慮這些問題。
我們也無需擔(dān)心意外的清理掉仍在使用的值,這會造成編譯器錯誤:所有權(quán)系統(tǒng)確保引用總是有效的,也會確保 drop
只會在值不再被使用時被調(diào)用一次。
現(xiàn)在我們學(xué)習(xí)了 Box<T>
和一些智能指針的特性,讓我們聊聊標(biāo)準庫中定義的其他幾種智能指針。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: