9.轻松入门Move: Ability
在前面几章我们一直在说对象的ability,那什么是ability呢? ability直译过来就是数据类型的能力。
Ability有四种,分别是key,store,copy,drop。基础数据类型和内建的数据类型的ability是默认的,不可修改的。他们默认有copy,drop,store这三种能力。结构体默认没有任何能力,但是我们可以自行设置结构体的能力。下面我主要讲解每种能力的含义和如何设置结构体的能力。
无论哪种ability,都是使用has关键字申明,具体如下:
#![allow(unused)] fn main() { //多个ability使用逗号隔开 public struct Person has key,store { id:UID, name: String, } }
Key Ability
有些资料说拥有key ability代表能在全局存储中作为key使用,这个并不适用于Move。关于key ability的作用官网如下描述:
On Sui, the
key
ability indicates that a struct is an object type and comes with an additional requirement that the first field of the struct has signatureid: UID
, to contain the object's unique address on-chain.
翻译过来:**如果一个类型,带有key ability就代表他是一个对象,并且要求这个结构体的第一个字段必须是id:UID。**这个id字段包含了这个对象在区块链上的地址。
如果我们定义了一个结构体有key ability,但是没有id字段或者id字段没在第一位置,编译都会报错:有key ability第一字段就必须是类型为UID的id。如下:
#![allow(unused)] fn main() { public struct Test3 has key { name: String } }
public struct Test3 has key {
--- The 'key' ability is used to declare objects in Sui
name: String
^^^^ Invalid object 'Test3'. Structs with the 'key' ability must have 'id: sui::object::UID' as their first field
所以key ability就是用来标识结构体是否是对象的。
Store Ability
key是对象必有的能力,而store则是对象可选的能力。有以下两种情况需要指定对象的store abiity:
- 1.当一个对象需要在定义他的模块之外被转交
- 2.当 一个结构体需要被嵌套的时候
如果你想限定某一个独有对象只能在定义它的模块内transfer,就无需予对象store ability。比如以下代码中的company对象,如果在定义他的模块外调用transfer方法,或者在命令行使用sui client transfer都会报错。
#![allow(unused)] fn main() { //没有store ability public struct Company has key { id: UID, person: Person, can_be_transfered: bool, } public struct Person has key,store { id:UID, name: String, } }
如果你想限定某个对象只有满足特定条件的时候才能转交,就可以自定义transfer方法,并且限定只能在模块内transfer,这样。实现如下:
#![allow(unused)] fn main() { const ECanNotTransfer = 1; //对象company没有store ability,只允许在定义对象的模块内transfer public struct Company has key { id: UID, person: Person, can_be_transfered: bool, } public struct Person has key,store { id:UID, name: String, } //自定义transfer方法 public fun transfer_company(company: Company, someone: address) { //只有can_be_transfered字段为true才可以transfer,否则退出程序 assert!(company.can_be_tra nsfered, ECanNotTransfer); transfer::transfer(company, someone); } }
如果是非对象结构体,想在对象中作为一个字段存储,也必须要有store能力。
Copy
与key ability相反,copy ability不能用于对象。copy ability 就是用于标记这个结构体是否可以被复制。
#![allow(unused)] fn main() { public struct Company has key { id: UID, person: Person, can_be_transfered: bool, } public struct Person has key,store { id:UID, name: String, } public entry fun new(ctx: &mut TxContext) { let person = Person { id: object::new(ctx), name: string::utf8(b"hanmeimei"), }; let company = Company { id: object::new(ctx), person: person, can_be_transfered: false, }; //使用关键词copy复制company对象 let _company2 = copy company; transfer::transfer(company, tx_context::sender(ctx)); transfer::transfer(_company2, tx_context::sender(ctx)) } }
编译报错:
那我们是不是加上copy ability就可以顺利通过编译呢???我们加上之后继续编译,报错如下:
如果要对一个结构体加上copy ability,那么这个结构体内所有字段都需要拥有该ability然而对象Company的id字段不具有copy ability,而这个id字段是每个对象都有的字段,所以可以得出结论:copy ability不能用于对象,只能用于非对象结构体。
值得注意的是在对结构体设置copy 、store 和drop能力的时候,都需要先确保结构体内所有字段包含这些能力。
Drop
跟copy同理,drop ability也只能用于非对象结构体。drop表明这个结构体是否能在作用域结束的时候自动删除。如果不能自动删除则需要手动调用删除逻辑。删除结构体的方法详见:6.轻松入门Move: 结构体
了解更多Move内容:
- telegram: t.me/move_cn
- QQ群: 79489587