对象所有权
每个对象都有一个所有者字段,指示如何拥有该对象。所有权决定了一个对象如何在事务中使用。有 4 种不同类型的所有权:
由一个地址拥有
这是 Move 对象最常见的情况。在 Move 代码中创建的 Move 对象可以转移到一个地址。转移后,该对象将归该地址所有。地址拥有的对象只能由该所有者地址签名的交易使用(即作为 Move 调用参数传递)。拥有的对象可以作为 Move 调用参数以 3 种形式中的任何一种传递:只读引用 ( &T)、可变引用 ( &mut T) 和按值 ( T)。重要的是要注意,即使一个对象通过只读引用传递(&T) 在 Move 调用中,仍然需要只有对象的所有者才能进行这样的调用。也就是说,在验证对象是否可以在交易中使用时,Move 调用的意图无关紧要,所有权才是最重要的。
module book::obj {
use sui::object::UID;
use sui::transfer;
use sui::tx_context::{Self, TxContext};
use sui::object;
public struct Obj has key {
id: UID,
}
fun init(ctx: &mut TxContext) {
let obj = Obj {
id: object::new(ctx)
};
transfer::transfer(obj, tx_context::sender(ctx))
}
}
由另一个对象拥有
一个对象可以由另一个对象拥有。将这种直接所有权与对象包装区分开来很重要。 当您将一个对象的结构定义的字段设置为另一种对象类型时,可以将一个对象包装/嵌入到另一个对象中。例如:
module sui::obj_inner {
use sui::object::{UID};
use sui::tx_context::{TxContext, sender};
use sui::object;
use sui::transfer;
public struct A has key,store{
id:UID
}
public struct B has key {
id:UID,
a: A
}
fun init(ctx:& mut TxContext){
let a = A{
id:object::new(ctx)
};
let b = B{
id:object::new(ctx),
a
};
transfer::transfer(b,sender(ctx));
}
}
定义一个对象类型A,该类型包含一个类型为另一个对象类型的字段B。在这种情况下, type 的对象B被包装到 type 的对象中A。使用对象包装,包装的对象(在本例中为 object b)不会作为顶级对象存储在 Sui 存储中,并且无法通过对象 ID 访问它。相反,它只是 type 对象的序列化字节内容的一部分A。你可以把一个对象被包装的情况想象成类似于被删除的情况,只不过它的内容仍然存在于另一个对象的某个地方。
现在回到另一个对象拥有的对象的主题。当一个对象为另一个对象所有时,它不会被包装。这意味着子对象仍然作为顶级对象独立存在,可以直接在 Sui 存储中访问。所有权关系仅通过子对象的所有者字段进行跟踪。如果您仍想观察子对象或能够在其他事务中使用它,这将很有用。Sui 提供库 API 来使一个对象为另一个对象所拥有。有关如何执行此操作的更多详细信息,请参阅Sui Move 库。
不可变的 常量
您不能改变不可变对象,并且不可变对象没有独占所有者。任何人都可以在 Sui Move 调用中使用不可变对象。
module book::obj {
use sui::object::UID;
use sui::transfer;
use sui::tx_context::{Self, TxContext};
use sui::object;
public struct Obj has key {
id: UID,
}
fun init(ctx: &mut TxContext) {
let obj = Obj {
id: object::new(ctx)
};
transfer::freeze_object(obj);
}
}
所有 Sui Move 包都是不可变对象:您无法在发布后更改 Sui Move 包。您可以使用freeze_object操作将 Sui Move 对象转换为不可变对象。您只能在 Sui Move 调用中将不可变对象作为只读引用 ( &T) 传递。
共享
对象可以共享,这意味着任何人都可以读取或写入该对象。与可变拥有的对象(单写者)相比,共享对象需要共识来排序读取和写入。有关创建和访问共享对象的示例,请参阅共享对象。
在其他区块链中,每个对象都是共享的。但是,Sui 程序员通常可以选择使用共享对象、拥有对象或组合来实现特定用例。这种选择可能会对性能、安全性和实施复杂性产生影响。理解这些权衡的最好方法是查看一些以两种方式实现的用例示例:
托管:共享,拥有 拍卖:共享,拥有 井字游戏:共享,拥有
module book::obj {
use sui::object::UID;
use sui::transfer;
use sui::tx_context::{Self, TxContext};
use sui::object;
public struct Obj has key {
id: UID,
}
fun init(ctx: &mut TxContext) {
let obj = Obj {
id: object::new(ctx)
};
transfer::share_object(obj);
}
}
module sui::transfer {
public fun transfer<T: key>(obj: T, recipient: address) {
transfer_impl(obj, recipient)
}
public fun public_transfer<T: key + store>(obj: T, recipient: address) {
transfer_impl(obj, recipient)
}
public fun freeze_object<T: key>(obj: T) {
freeze_object_impl(obj)
}
public fun public_freeze_object<T: key + store>(obj: T) {
freeze_object_impl(obj)
}
public fun share_object<T: key>(obj: T) {
share_object_impl(obj)
}
public fun public_share_object<T: key + store>(obj: T) {
share_object_impl(obj)
}
}
key + store
- 你会看到 关于所有权专业的方法其实有两组
- public_* 开头的函数 和没有 public的函数,那么什么时候使用
public_*
开头的函数呢
简单来说就是如果 定义的对象是 通用资产 就是 key + store 就用
public_*
开头的函数
module book::obj {
use sui::object::UID;
use sui::transfer;
use sui::tx_context::{Self, TxContext};
use sui::object;
public struct Obj has key , store {
id: UID,
}
fun init(ctx: &mut TxContext) {
let obj = Obj {
id: object::new(ctx)
};
transfer::public_transfer(obj, tx_context::sender(ctx))
}
}
详细讲解
- https://examples.sui.io/basics/transfer.html
- https://examples.sui.io/basics/custom-transfer.html
参考文档
- https://docs.sui.io/build/programming-with-objects/ch1-object-basics
- https://docs.sui.io/learn/objects
- https://www.notion.so/706community/2-1-Object-3f2aeeefccf447d295375d803379f136?pvs=4