Skip to main content

中斷執行

交易不是成功就是失敗。成功的執行會套用對物件和鏈上資料所做的所有更改,並將交易提交到區塊鏈。或者,如果交易中斷,則不會套用更改。使用 abort 關鍵字來中斷交易並還原所做的任何更改。

值得注意的是,Move 中沒有擷取 (catch) 機制。如果交易中斷,迄今為止所做的更改將被還原,並且該交易被視為失敗。

中斷 (Abort)

abort 關鍵字用於中斷交易的執行。它與中斷碼 (abort code) 結合使用,中斷碼會返回給交易的呼叫者。中斷碼是一個 u64 類型的 整數

let user_has_access = false;

// 如果 `user_has_access` 為 false,則以預定義常數中止
if (!user_has_access) {
abort 1
};

上面的程式碼當然會以中斷碼 1 中斷。

assert!

assert! 巨集是一個內建巨集,可用於斷言一個條件。如果條件為 false,交易將以給定的中斷碼中斷。assert! 巨集是在條件不滿足時中斷交易的便捷方式。該巨集縮短了原本使用 if 表達式 + abort 編寫的程式碼。code 參數是可選的,但必須是一個 u64 值或一個 #[error](有關更多資訊,請參見下文)。

// 如果 `user_has_access` 為 `false`,則以中止碼 0 中止
assert!(user_has_access, 0);

// 展開為:
if (!user_has_access) {
abort 0
};

錯誤常數

為了使錯誤程式碼更具描述性,定義 錯誤常數 是一個很好的做法。錯誤常數被定義為 const 宣告,通常以 E 開頭,後接大駝峰式 (camel case) 名稱。錯誤常數與其他常數類似,沒有任何特殊處理。但是,它們通常用於提高程式碼的可讀性,並使中斷情境更容易理解。

/// 使用者無存取權限時的錯誤碼。
const ENoAccess: u64 = 0;
/// 嘗試存取不存在的欄位。
const ENoField: u64 = 1;

/// 更新一筆記錄。
public fun update_record(/* ... , */ user_has_access: bool, field_exists: bool) {
// 現在 assert 會更容易閱讀
assert!(user_has_access, ENoAccess);
assert!(field_exists, ENoField);

/* ... */
}

錯誤訊息

Move 2024 引入了一種特殊類型的錯誤常數,標有 #[error] 屬性。此屬性允許錯誤常數為 vector<u8> 類型,並可用於儲存錯誤訊息。

#[error]
const ENotAuthorized: vector<u8> = b"The user is not authorized to perform this action";

#[error]
const EValueTooLow: vector<u8> = b"The value is too low, it should be at least 10";

/// 代表使用者執行操作。
public fun update_value(user: &mut User, value: u64) {
assert!(user.is_authorized, ENotAuthorized);
assert!(value >= 10, EValueTooLow);

user.value = value;
}

延伸閱讀