能力:簡介 (Abilities: Introduction)
Move 有一套獨特的型別系統,其中每個型別會宣告其值允許執行的操作。在上一節中,每個 Artist 與 Record 執行個體都必須被使用:儲存、傳遞或解構——捨棄或複製值都不是可行選項。這不是刻意的嚴格限制。預設情況下,Move 值只能被建立、移動與拆解;超出這些範圍的操作,都是型別必須明確獲得的權限。這些權限稱為「能力」(abilities)。
什麼是能力? (What are Abilities?)
能力是型別所具備的權限。它們會作為 struct 定義的一部分被宣告,編譯器會拒絕型別未獲准執行的任何操作。能力不會為型別本身增加任何功能——它會解鎖原本會造成編譯錯誤的行為。
Move 有四種能力。其中兩種控制值在執行期間可以發生什麼事:
- copy - 值可以被複製;
- drop - 值可以被捨棄;
另兩種則控制儲存:
- key - 值可以作為儲存單位——在 Sui 上即為物件;
- store - 值可以儲存在其他位於儲存空間中的值內部。
這種「預設拒絕」的設計,讓 Move 型別能忠實地建模資產:沒有 copy 的型別無法被複製,沒有 drop 的型別也不會遺失——這些保證是具有一般可自由複製值的語言無法提供的。
在本書中,你會看到名為 Ability: <name> 的章節,各自詳細說明一種能力:其運作方式與使用時機。
能力語法 (Abilities Syntax)
能力會使用 has 關鍵字,在 struct 定義中以逗號分隔的能力清單設定:
/// This struct has the `copy` and `drop` abilities.
public struct VeryAble has copy, drop {
/// The fields must support the abilities of the struct:
/// `u64` has `copy` and `drop` (and more).
value: u64,
}
這兩項已宣告的能力會改變 VeryAble 執行個體的行為。請將下列程式碼與上一節中的封裝與解構流程比較:
let a = VeryAble { value: 10 };
// `copy`: `a` is copied into `b` - both are usable afterwards.
let b = a;
assert_eq!(a.value, b.value);
// `drop`: neither value has to be stored or unpacked; both are
// silently discarded at the end of the function.
現在,讓我們依序快速了解全部四種能力。
drop:捨棄值 (drop: Discarding Values)
drop 能力允許執行個體被捨棄:指派給未使用的變數、使用 _ 萬用字元忽略,或在作用域結束時直接遺留。換句話說,drop 讓型別的行為如同多數其他程式語言中的值。它適用於代表一般資料的型別;缺少它則可保護代表資產的型別。下一節專門說明此能力。
copy:複製值 (copy: Duplicating Values)
copy 能力允許執行個體被複製,可以由編譯器隱式複製,或使用 copy 關鍵字明確複製。所有原始型別——整數、bool、address——都如同具備此能力。請注意,copy 幾乎總是與 drop 一同出現:能複製卻不能捨棄的值,會強迫其每一份複本都必須被使用。詳細內容請見能力:複製章節。
key:物件與儲存 (key: Objects and Storage)
key 能力將型別標示為儲存單位:執行個體可以寫入區塊鏈狀態,並透過其唯一識別碼——也就是它的「key」——在之後找到。在 Sui 上,具有 key 能力的 struct 稱為物件,且第一個欄位必須為 id: UID。物件是 Sui 程式設計模型的核心,完整的物件模型章節專門說明物件,後續還有能力:鍵說明此能力本身。
store:儲存於物件內 (store: Storing Inside Objects)
store 能力允許執行個體儲存在其他最終會進入儲存空間的 struct 內部。key 讓型別成為區塊鏈狀態中的頂層記錄,而 store 則允許型別成為其中的一部分。詳情請見能力:儲存章節。
能力來自欄位 (Abilities Come from Fields)
能力是對整個值(包含其內容)的承諾,因此 struct 只有在其所有欄位型別都支援時,才能被賦予某項能力。具有 copy 的 struct 要求每個欄位都具備 copy;drop 與 store 也是如此;key 則要求每個欄位都具備 store。編譯器會在定義處強制執行此規則,因此下列程式碼無法編譯:
public struct NoAbilities {}
public struct Wrapper has copy, drop {
inner: NoAbilities,
// ^ 錯誤!此 struct 已宣告具備 'copy' 能力
// 因此所有欄位都必須具備 'copy' 能力
}
除了參考以外,所有內建型別都具有 copy、drop 與 store 能力;參考則具有 copy 與 drop。如 vector 與 Option 等容器型別會有條件地支援 copy、drop 與 store——vector 只有在其元素可以被複製時才能被複製。
無能力 (No Abilities)
沒有能力的 struct 無法被捨棄、複製或儲存在儲存空間中。我們將這類 struct 稱為燙手山芋(Hot Potato)。這是個輕鬆的名稱,但有助於記住:沒有能力的 struct 就像燙手山芋——只能被傳遞,且需要特殊處理。燙手山芋是 Move 中最強大的模式之一;我們會在燙手山芋模式章節中更深入說明。
延伸閱讀 (Further Reading)
- Move 參考文件中的型別能力。