Skip to main content

Abilities:Drop 能力 (Abilities: Drop)

在大多數程式語言中,不對一個值做任何事並不是問題:未使用的變數頂多觸發一個警告,一旦離開作用域就會被遺忘。在 Move 中,正如我們在 Struct 章節看到的,預設行為恰恰相反:struct 值必須被_使用_——儲存在某處、傳遞下去,或被拆解——而一個默默丟棄某個值的程式無法通過編譯。

drop 能力——四種能力中最簡單的一個——是這條規則的選擇退出機制。擁有 drop 的 struct 可以被_忽略_或_丟棄_:綁定到一個永遠不會被讀取的變數、用 _ 萬用字元忽略,或是在其作用域結束時單純被留下不管。換句話說,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 能力只允許_丟棄_一個值。它不允許複製或儲存該值——這些行為分別由獨立的 copystore 能力所管控。

何時使用 drop (When to Use drop)

一個不錯的經驗法則:drop 應該屬於代表_資料_的型別,而它的缺席則保護了代表_資產_或_義務_的型別。

設定值、中繼資料、運算的中間結果——這些都不值得被保護,強迫程式設計師明確銷毀每一個都純屬形式。賦予這類型別 drop 能力能讓程式碼保持簡潔。集合型別就是一個很好的例子:因為 vector 擁有 drop(當其內容也擁有時),一個數字的 vector 在不再需要時可以直接被遺忘。

另一方面,缺少 drop 是 Move 型別系統的核心特徵之一。一枚代幣、一張票券、一張收據、一個償還義務——像這樣的值絕不能默默消失,而沒有 drop 的型別在編譯器層級保證了這一點:無論誰持有該值,都會被_強迫_對它做出有意義的處理。編譯器強制執行的值處理,正是前一節提到的 Hot Potato 模式的基礎,我們將在 Ownership and Scope 章節探討值如何在作用域之間移動的完整規則。

一個只擁有 drop 作為單一能力的 struct 稱為 Witness。我們會在 Witness and Abstract Implementation 章節解釋 Witness 的概念。

擁有 drop 能力的型別 (Types with the drop Ability)

Move 中所有原生型別都擁有 drop 能力。這包括:

標準函式庫中定義的所有型別同樣擁有 drop 能力。這包括:

請注意這份清單中的模式:像 vectorOption 這樣的容器型別,只有在其內容可以被丟棄時才能被丟棄。如果 vector 的元素被保護而無法丟棄,那麼持有它們的 vector 也會受到保護——否則丟棄容器就會成為丟棄其內容的漏洞。

延伸閱讀 (Further Reading)