Move对象的有4种能力(abliity)1.对象的几种存储状态:新建的对象,进入未曾存储状态,一个交易结束之后,对象要么被销毁,要么被存储到网络的链上存储。链上存储的对象,也可以借用引用参与交易运算运行态的对象,可以通过share或freeze编程共享对象。freeze
新建的对象, 进入未曾存储状态,一个交易结束之后,对象要么被销毁,要么被存储到网络的链上存储。
链上存储的对象,也可以借用引用参与交易运算
运行态的对象,可以通过share或freeze 编程共享对象。freeze的对象是只读的。
链上存储对象,可以通过函数调用作为输入参数,移动成运行态,进入运行态之后,又可以重新进入析构或重新存到链上。
这四种能力是:
copy
drop
store
key
允许类型用作存储的 “key”。表面上,这意味着该值可以是 存储中的顶级价值;换句话说,它不需要包含在另一个值中,以 在仓库里。
对于 Sui,用于表示对象。
上图中27行,c对象被拷贝到d,c和d指向的不是同一个对象,
28 行修改了d,但是c没有被修改
32行和33行中,c和d取值不同.
第111 行中出现编译错误,因为 c 指向的对象已经转移到了d
public struct NonCopyable {
value :u64,
}
#[test]
fun test_non_copy(){
let c = NonCopyable{ value:33};
let d =c ;
std::debug::print(&c); //此时c对象已经被移动给d
std::debug::print(&d);
// sui::test_utils::destroy(c);
sui::test_utils::destroy(d);
}
public struct IgnoreMe has drop{
a:u32,
b:u32
}
#[test]
fun test_ignore(){
let im = IgnoreMe{a:3,b:4};
print(&im);
}
上文定义的IgnoreMe 对象im 具有自动析构的能力has drop
,在离开函数的作用域时候自动析构.
public struct NoDrop{ value :u64 }
#[test]
fun test_nodrop(){
let no_drop = NoDrop{ value :34};
print(&no_drop);
let NoDrop{ value: _ } = no_drop;
}
这个例子 NoDrop类型没有drop能力,对象离开作用域,需要析构,或者将对象的所有权转移.
fun useNoDrop(o : NoDrop ) : NoDrop{
std::debug::print(&o);
o
}
#[test]
fun testUseNoDrop(){
let o = NoDrop{value :4};
let d = useNoDrop(o);
NoDrop{value:_} = d;
}
对象独立存储在链上,必须具有key能力 has key
public struct Keyable has key{
id : UID,
}
#[test]
fun test_key(){
let mut ctx = tx_context ::dummy();
let k = Keyable{ id: object::new(&mut ctx)};
std::debug::print(&k);
transfer::transfer(k,ctx.sender());
}
这个例子中Keyable是具有key能力的,可以通过transfer传递到sui网络上存储, 指定owner地址.
use std::string::String;
public struct Grandson has store{
name : String,
}
public struct Child has store{
name : String,
child : Grandson,
}
public struct Parent has key{
id: UID,
child: Child,
}
#[test]
fun test_store_child(){
let mut ctx = tx_context::dummy();
let foo = Parent {
id : object::new(&mut ctx),
child: Child {
name : b"one child".to_string(),
child: Grandson{
name : b"a grandson".to_string(),
},
}
};
std::debug::print(&foo);
transfer::freeze_object(foo);
}
Parent是独立存储,具有key能力
Child 都是作为独立存储对象Parent的字段
Grandson 作为Child的字段存储在链上,
Child 和Grandson 都具有store能力
一个对象,没有任何ability ,就是hot potato
没有key 和store 无法保存在链上
没有drop 不会自动析构
只能在本模块析构, 因为外部模块无法直接访问struct的字段
下图中模块A, 需要使用模块B中的Foo 对象,使用完毕需要调用模块B 的析构方法
public struct Foo {
value :u32
}
module book::loan;
//hot potato pattern
public struct Loan{
feedback: u64, //还钱数
}
public struct Coin has key,store{
id:UID,
amount:u64
}
//借出钱
public fun borrow(amount:u64,ctx:&mut TxContext) :(Coin,Loan){
let feedback = amount * 103 /100;
let c = Coin{ id: object::new(ctx),amount};
(c, Loan{feedback})
}
const ErrNotEnoughFeedback:u64 = 43;
const OWNER_ADDR :address = @0xafe36044ef56d22494bfe6231e78dd128f097693f2d974761ee4d649e61f5fa2;//todo
public fun repay(coin: Coin,loan:Loan){
assert!(coin.amount >= loan.feedback,ErrNotEnoughFeedback);
transfer::public_transfer(coin,OWNER_ADDR);
Loan{ feedback:_} = loan;
}
``` {.line-numbers}
下面是借方模块的代码,使用测试代码演示
```c++
#[test_only]
module book::test_loan;
use book::loan::Coin;
////todo 贷款后赚钱的业务逻辑,这里没有实现
fun earn_money(coin : Coin ) :Coin{
coin
}
#[test]
#[expected_failure(abort_code=book::loan::ErrNotEnoughFeedback)]
fun borrow_test(){
let mut ctx = tx_context::dummy();
let (coin,loan) = book::loan::borrow(233,&mut ctx);
let new_money = earn_money(coin);
book::loan::repay(new_money,loan);
//todo 赚钱了,可以把feedback-amount 的钱,存入自己钱包
}
目前其他模块存到链上的对象,都需要key+store能力
public fun public_transfer<T: key + store>(obj: T, recipient: address) {
transfer_impl(obj, recipient)
}
public fun public_freeze_object<T: key + store>(obj: T) {
freeze_object_impl(obj)
}
public fun public_share_object<T: key + store>(obj: T) {
share_object_impl(obj)
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!