前章で説明したストレージ操作はデフォルトで制限されており、オブジェクトを定義するモジュール内でのみ呼び出せる。言い換えれば、タイプはモジュール内部にあり、ストレージ操作で使用される必要がある。この制限はSui Verifierにおいて実装されており、バイトコードレベルで強制される。
ただし、オブジェクトを他のモジュールでトランスファーおよび保存できるようにするためには、これらの制限を緩和することができる。sui::transfer
モジュールは、他のモジュールでのストレージ操作の呼び出しを許可する一連のpublic_*関数を提供している。その関数はpublic_
でプレフィックスされ、すべてのモジュールおよびトランザクションが利用できる。
sui::transfer
モジュールは次の公開関数を与える。これらは既に説明したものとほぼ同じだが、任意のモジュールから呼び出すことができる。
// File: sui-framework/sources/transfer.move
/// Public version of the `transfer` function.
public fun public_transfer<T: key + store>(object: T, to: address) {}
/// Public version of the `share_object` function.
public fun public_share_object<T: key + store>(object: T) {}
/// Public version of the `freeze_object` function.
public fun public_freeze_object<T: key + store>(object: T) {}
これらの関数の使い方を説明するために、次の例を考えよう。:モジュールAはキー(key
)アビリティを持つオブジェクトKとキー+ストア(key + store
)アビリティを持つオブジェクトKSを定義し、モジュールBはこれらのオブジェクトに対してトランスファー(transfer
)関数を実装しようとする。
<aside>
💡 この例ではtransfer::transfer
を使うが、動作についてはshare_object
、freeze_object
関数でも同じである。
</aside>
/// Defines `ObjectK` and `ObjectKS` with `key` and `key + store`
/// abilities respectively
module book::transfer_a {
public struct ObjectK has key { id: UID }
public struct ObjectKS has key, store { id: UID }
}
/// Imports the `ObjectK` and `ObjectKS` types from `transfer_a` and attempts
/// to implement different `transfer` functions for them
module book::transfer_b {
// types are not internal to this module
use book::transfer_a::{ObjectK, ObjectKS};
// Fails! ObjectK is not `store`, and ObjectK is not internal to this module
public fun transfer_k(k: ObjectK, to: address) {
sui::transfer::transfer(k, to);
}
// Fails! ObjectKS has `store` but the function is not public
public fun transfer_ks(ks: ObjectKS, to: address) {
sui::transfer::transfer(ks, to);
}
// Fails! ObjectK is not `store`, `public_transfer` requires `store`
public fun public_transfer_k(k: ObjectK) {
sui::transfer::public_transfer(k);
}
// Works! ObjectKS has `store` and the function is public
public fun public_transfer_ks(y: ObjectKS, to: address) {
sui::transfer::public_transfer(y, to);
}
}
上の例を拡大すると、
transfer_b
の内部ではないので、transfer_k
は失敗する。transfer_b
の内部ではないため、transfer_ks
は失敗する。store
)アビリティを持っていないため、public_transfer_k
は失敗する。store
)アビリティを持ち、トランスファーが公開されているため、public_transfer_ks
は機能する。ストア(store
)アビリティをタイプに追加するかどうかの判断は慎重に行った方が良い。一方では、他のアプリケーションで型を使用可能にするため、それは事実上必要なものである。もう一方では、意図されたストレージモデルをラップして変更することを可能とする。
例えば、キャラクターはアカウントにより所有されることを意図しているかもしれないが、ストア(store
)アビリティによって凍結されてしまう(共有不可であり、この変更は制限される)可能性がある。
The Move Book へ戻る