能力:丟棄 (Abilities: Drop)
在大多數程式語言中,不對某個值進行任何處理並不是問題:未使用的變數至多可能觸發警告,並會在其離開作用域的瞬間被遺忘。如同我們在 結構 (Struct) 章節所見,在 Move 中預設情況恰好相反:結構值必須被 使用——儲存在某處、傳遞出去,或解構——而靜默丟棄值的程式無法編譯。
drop 能力——四種能力中最簡單的一種——可讓你不遵守此規則。具有 drop 的結構可被 忽略 或 丟棄:繫結至永不讀取的變數、以 _ 萬用字元忽略,或在其作用域結束時直接留下。換言之,drop 讓 Move 型別的行為方式如同大多數其他語言中的值:
module book::drop_ability;
/// This struct has the `drop` ability.
public struct IgnoreMe has drop {
a: u8,
b: u8,
}
/// This struct does not have the `drop` ability.
public struct NoDrop {}
#[test]
// Create an instance of the `IgnoreMe` struct and ignore it.
// Even though we constructed the instance, we don't need to unpack it.
fun test_ignore() {
let no_drop = NoDrop {};
let _ = IgnoreMe { a: 1, b: 2 }; // no need to unpack
// The value must be unpacked for the code to compile.
let NoDrop {} = no_drop; // OK
}
在上述範例中,IgnoreMe 執行個體被指定給 _,且從未解構——程式碼可以編譯,因為 IgnoreMe 具有 drop 能力。NoDrop 執行個體無法以這種方式處理:僅有兩種選擇,保留它或解構它,而測試會在最後一行將其解構。
何時使用 drop (When to Use drop)
一項實用原則:drop 適用於表示 資料 的型別;缺少它則可保護表示 資產 或 義務 的型別。
設定值、中繼資料、計算的中間結果——這些都不值得保護,強迫程式設計者明確銷毀每一個值只會徒增儀式感。為這類型別賦予 drop 能力可讓程式碼保持簡潔。集合型別是很好的範例:由於 vector 具有 drop(當其內容也具有時),不再需要的數字向量可以直接被遺忘。
另一方面,缺少 drop 是 Move 型別系統的定義性特徵之一。硬幣、票券、收據、償還義務——這類值絕不可靜默消失,而不具備 drop 的型別可在編譯器層級提供此保證:持有該值的人會被 強制 對其進行有意義的處理。由編譯器強制處理值,是熱馬鈴薯模式 (Hot Potato pattern) 的基礎;該模式已在前一節 (previous section) 提及,而我們會在所有權與作用域 (Ownership and Scope) 章節中探討值如何在作用域之間移動的完整規則。
僅具有 drop 一種能力的結構稱為 Witness。我們會在見證與抽象實作 (Witness and Abstract Implementation) 章節中說明 Witness 的概念。
具有 drop 能力的型別 (Types with the drop Ability)
Move 中所有原生型別都具有 drop 能力。包括:
標準函式庫中定義的所有型別也都具有 drop 能力。包括:
請注意清單中的模式:如 vector 或 Option 的容器型別,只有在其內容可被丟棄時才能被丟棄。若向量中的元素受到保護而不可丟棄,持有它們的向量也會受到保護——否則丟棄容器將成為丟棄其內容的漏洞。
延伸閱讀 (Further Reading)
- Move 參考文件中的型別能力 (Type Abilities)。