中止执行
在 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 + abort
,assert!
使代码更简洁易读。
示例
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
的错误消息。
这些错误消息不仅提高了代码的可读性,还方便了交易调用者调试。
总结
abort
关键字用于显式中止交易,并返回一个中止代码。assert!
宏提供了一种便捷的方式,在不满足条件时快速中止交易。- 错误常量和错误消息使得错误处理更具描述性,增强了代码的可读性和可维护性。