Skip to content

中止执行

在 Move 中,交易的执行有两种可能的结果:成功或中止。

  • 成功执行 会将所有对链上对象和数据的更改提交到区块链。
  • 中止执行 则会撤销所有更改,并将交易标记为失败。

Move 使用 abort 关键字来中止交易,同时返回一个中止代码供调用者查看。需要注意的是,Move 不支持 catch 机制,因此一旦中止,交易的所有更改都会被回滚。

abort 关键字

abort 关键字用于显式中止交易。它需要一个 u64 类型的中止代码作为参数,这个代码会被返回给调用者。

示例

move
let user_has_access = true;

// 如果用户无权限,使用中止代码 0 中止交易
if (!user_has_access) {
    abort 0;
}

// 另一种语法形式,使用括号
if (user_has_access) {
    abort(1);
}

在上面的示例中,根据条件判断是否中止交易,并指定中止代码。中止代码可用于诊断错误原因。

assert! 宏

assert! 是 Move 提供的一个便捷宏,用于断言某个条件为真。如果条件为假,则自动中止交易并返回指定的中止代码。相比手动使用 if + abortassert! 使代码更简洁易读。

示例

move
// 如果用户无权限,使用中止代码 0 中止交易
assert!(user_has_access, 0);

// 等价于:
if (!user_has_access) {
    abort 0;
}

assert! 的第二个参数是中止代码,类型为 u64,也可以是带有 #[error] 标记的常量(详见下文)。

错误常量

为了提高代码的可读性和维护性,推荐使用错误常量来表示中止代码。错误常量是通过 const 声明的,通常以 E 为前缀,后跟描述性名称(驼峰式命名)。这使得错误原因更容易理解。

示例

move
/// 用户无权限时的错误代码
const ENoAccess: u64 = 0;

/// 尝试访问不存在的字段
const ENoField: u64 = 1;

/// 更新记录
public fun update_record(user_has_access: bool, field_exists: bool) {
    // 使用错误常量提高可读性
    assert!(user_has_access, ENoAccess);
    assert!(field_exists, ENoField);
    // 继续处理逻辑...
}

通过这种方式,即使代码复杂,开发者仍能快速理解不同中止场景的含义。

错误消息

Move 2024 引入了带有 #[error] 属性的特殊错误常量,支持存储更详细的错误消息。这些常量类型为 vector<u8>,用于在中止时提供更具描述性的错误信息。

示例

move
#[error]
const ENotAuthorized: vector<u8> = b"用户无权执行此操作";

#[error]
const EValueTooLow: vector<u8> = b"值太低,应至少为 10";

/// 更新用户的值
public fun update_value(user: &mut User, value: u64) {
    assert!(user.is_authorized, ENotAuthorized); // 验证用户权限
    assert!(value >= 10, EValueTooLow);         // 验证值是否符合要求
    user.value = value;
}

在此示例中:

  • 当用户无权限时,中止交易并返回 ENotAuthorized 的错误消息。
  • 当提供的值过低时,中止交易并返回 EValueTooLow 的错误消息。

这些错误消息不仅提高了代码的可读性,还方便了交易调用者调试。

总结

  1. abort 关键字用于显式中止交易,并返回一个中止代码。
  2. assert! 宏提供了一种便捷的方式,在不满足条件时快速中止交易。
  3. 错误常量和错误消息使得错误处理更具描述性,增强了代码的可读性和可维护性。