Previous << Paths
Next >> Capabilities
Accountは、リソースや構造体などの保存可能なオブジェクトを保存することができます。
Accountは、storage
フィールドを通じてストレージを公開します。このフィールドの型はAccount.Storage
です。
Account.Storage
access(all)
struct Storage {
/* The current amount of storage used by the account in bytes. */
access(all)
let used: UInt64
/* The storage capacity of the account in bytes. */
access(all)
let capacity: UInt64
/* All public paths of this account. */
access(all)
let publicPaths: [PublicPath]
/* All storage paths of this account. */
access(all)
let storagePaths: [StoragePath]
/** Saves the given object into the account's storage at the given path.
*
* Resources are moved into storage, and structures are copied.
*
* If there is already an object stored under the given path, the program aborts.
*
* The path must be a storage path, i.e., only the domain `storage` is allowed.
*/
access(Storage | SaveValue)
fun save<T: Storable>(_ value: T, to: StoragePath)
/** Reads the type of an object from the account's storage which is stored under the given path,
* or nil if no object is stored under the given path.
*
* If there is an object stored, the type of the object is returned without modifying the stored object.
*
* The path must be a storage path, i.e., only the domain `storage` is allowed.
*/
access(all)
view fun type(at path: StoragePath): Type?
/** Loads an object from the account's storage which is stored under the given path,
* or nil if no object is stored under the given path.
*
* If there is an object stored,
* the stored resource or structure is moved out of storage and returned as an optional.
*
* When the function returns, the storage no longer contains an object under the given path.
*
* The given type must be a supertype of the type of the loaded object.
* If it is not, the function panics.
*
* The given type must not necessarily be exactly the same as the type of the loaded object.
*
* The path must be a storage path, i.e., only the domain `storage` is allowed.
*/
access(Storage | LoadValue)
fun load<T: Storable>(from: StoragePath): T?
/** Returns a copy of a structure stored in account storage under the given path,
* without removing it from storage,
* or nil if no object is stored under the given path.
*
* If there is a structure stored, it is copied.
* The structure stays stored in storage after the function returns.
*
* The given type must be a supertype of the type of the copied structure.
* If it is not, the function panics.
*
* The given type must not necessarily be exactly the same as the type of the copied structure.
*
* The path must be a storage path, i.e., only the domain `storage` is allowed.
*/
access(Storage | CopyValue)
view fun copy<T: AnyStruct>(from: StoragePath): T?
/** Returns true if the object in account storage under the given path satisfies the given type,
* i.e. could be borrowed using the given type.
*
* The given type must not necessarily be exactly the same as the type of the borrowed object.
*
* The path must be a storage path, i.e., only the domain `storage` is allowed.
*/
access(all)
view fun check<T: Any>(from: StoragePath): Bool
/** Returns a reference to an object in storage without removing it from storage.
*
* If no object is stored under the given path, the function returns nil.
* If there is an object stored, a reference is returned as an optional,
* provided it can be borrowed using the given type.
* If the stored object cannot be borrowed using the given type, the function panics.
*
* The given type must not necessarily be exactly the same as the type of the borrowed object.
*
* The path must be a storage path, i.e., only the domain `storage` is allowed
*/
access(Storage | BorrowValue)
view fun borrow<T: &Any>(from: StoragePath): T?
/** Iterate over all the public paths of an account,
* passing each path and type in turn to the provided callback function.
*
* The callback function takes two arguments:
* 1. The path of the stored object
* 2. The run-time type of that object
*
* Iteration is stopped early if the callback function returns `false`.
*
* The order of iteration is undefined.
*
* If an object is stored under a new public path,
* or an existing object is removed from a public path,
* then the callback must stop iteration by returning false.
* Otherwise, iteration aborts.
*/
access(all)
fun forEachPublic(_ function: fun(PublicPath, Type): Bool)
/** Iterate over all the stored paths of an account,
* passing each path and type in turn to the provided callback function.
*
* The callback function takes two arguments:
* 1. The path of the stored object
* 2. The run-time type of that object
*
* Iteration is stopped early if the callback function returns `false`.
*
* If an object is stored under a new storage path,
* or an existing object is removed from a storage path,
* then the callback must stop iteration by returning false.
* Otherwise, iteration aborts.
*/
access(all)
fun forEachStored(_ function: fun (StoragePath, Type): Bool)
}
entitlement Storage
entitlement SaveValue
entitlement LoadValue
entitlement CopyValue
entitlement BorrowValue
Saving objects
access(Storage | SaveValue)
fun save<T: Storable>(_ value: T, to: StoragePath)
save
関数は、オブジェクトをアカウントストレージに保存します。この関数はリソースを移動し、構造体をコピーします。指定されたパスにすでにオブジェクトが保存されている場合、プログラムは中止します。パスはストレージパスでなければならずドメインストレージでなければなりません。
T
はオブジェクトタイプの型パラメータです。Cadenceは、この型パラメータを引数の型から推論できます。
Getting object type information
access(all)
view fun type(at path: StoragePath): Type?
type
関数は、指定されたパスに格納されているオブジェクトのタイプを返します。または、アカウントが指定されたパスにオブジェクトを格納していない場合はnil
を返します。
この関数は、格納されているオブジェクトを変更しません。
パスはストレージパスでなければならず、ドメインストレージでなければなりません。
Removing objects
access(Storage | LoadValue)
fun load<T: Storable>(from: StoragePath): T?
load
関数は、アカウントストレージからオブジェクトをロードします。指定されたパスにオブジェクトが格納されている場合、関数はストレージから格納されたリソースまたは構造体を移動し、オプショナルとしてそれを返します。指定されたパスにオブジェクトが格納されていない場合、関数はnil
を返します。関数がオブジェクトを返す場合、ストレージは指定されたパスにオブジェクトを格納しなくなります。
T
はオブジェクトの型を表す型パラメータです。プログラムでは、このパラメータに型引数を明示的に指定する必要があります。
型T
は、ロードされたオブジェクトの型のスーパータイプでなければなりません。そうでない場合は、プログラムが中断します。指定された型は、ロードされたオブジェクトの型と必ずしも完全に一致する必要はありません。
パスはストレージパスでなければならず、ドメインストレージを持たなければなりません。
Copying objects
access(Storage | CopyValue)
view fun copy<T: AnyStruct>(from: StoragePath): T?
copy
関数は、アカウントストレージに保存されている構造体のコピーを、ストレージから削除せずに返します。指定されたパスに構造体が保存されている場合、この関数は保存されている構造体をコピーし、オプショナルとして返します。指定されたパスに構造体が保存されていない場合、この関数はnil
を返します。この関数がオブジェクトを返す場合、関数の戻り値として返された後も構造体はストレージに保存されたままになります。
T
は構造体の型を表す型パラメータです。プログラムでは、パラメータに型引数を明示的に指定する必要があります。
型T
は、コピーされる構造体の型のスーパータイプでなければなりません。そうでない場合は、プログラムが中断します。指定する型は、コピーされる構造体の型と必ずしも完全に一致している必要はありません。
パスはストレージパスでなければならず、ドメインストレージでなければなりません。
Accessing objects
access(Storage | BorrowValue)
view fun borrow<T: &Any>(from: StoragePath): T?
access(Storage | BorrowValue)
view fun borrow<T: &Any>(from: StoragePath): T?
borrow
関数は、ストレージに保存されたオブジェクトへの参照を返します。この関数を使用すると、オブジェクトをストレージから移動させることなく、ストレージ内のオブジェクトを簡単に操作することができます。
指定されたパスに構造体が保存されている場合、この関数はオブジェクトへの参照を作成し、オプショナルとしてその参照を返します。指定されたパスに構造体が保存されていない場合、この関数はnil
を返します。
T
はオブジェクトの型を表す型パラメータです。プログラムでは、パラメータに型引数を明示的に指定する必要があります。
型引数は、any
型、すなわち &Any
(Anyはすべての型のスーパータイプです)への参照である必要があります。型T
は借用するオブジェクトの型のスーパータイプでなければなりません。そうでない場合、プログラムは中断します。指定する型は、必ずしも借用するオブジェクトの型と完全に一致している必要はありません。
パスはストレージパスでなければならず、ドメインストレージでなければなりません。
Example
/* Declare a resource interface named `HasCount`, that has a field `count` */
resource interface HasCount {
count: Int
}
/* Declare a resource named `Counter` that conforms to `HasCount` */
resource Counter: HasCount {
access(all)
var count: Int
access(all)
init(count: Int) {
self.count = count
}
}
/* In this example, an authorized reference to an account
is available through the constant `account`. */
/* Create a new instance of the resource type `Counter`
* and save it in the storage of the account.
*
* The path `\/storage\/counter` is used to refer to the stored value.
* Its identifier `counter` was chosen freely and could be something else.
*/
account.storage.save(
<-create Counter(count: 42),
to: /storage/counter
)
/* Run-time error: Storage already contains an object under path `\/storage\/counter` */
account.storage.save(
<-create Counter(count: 123),
to: /storage/counter
)
/* Load the `Counter` resource from storage path `\/storage\/counter`.
*
* The new constant `counter` has the type `Counter?`, i.e., it is an optional,
* and its value is the counter resource, that was saved at the beginning
* of the example.
*/
let counter <- account.storage.load<@Counter>(from: /storage/counter)
/* The storage is now empty, there is no longer an object stored
under the path `\/storage\/counter`. */
/* Load the `Counter` resource again from storage path `\/storage\/counter`.
*
* The new constant `counter2` has the type `Counter?` and is `nil`,
* as nothing is stored under the path `\/storage\/counter` anymore,
* because the previous load moved the counter out of storage.
*/
let counter2 <- account.storage.load<@Counter>(from: /storage/counter)
/* Create another new instance of the resource type `Counter`
* and save it in the storage of the account.
*
* The path `\/storage\/otherCounter` is used to refer to the stored value.
*/
account.storage.save(
<-create Counter(count: 123),
to: /storage/otherCounter
)
/* Load the `Vault` resource from storage path `\/storage\/otherCounter`.
*
* The new constant `vault` has the type `Vault?` and its value is `nil`,
* as there is a resource with type `Counter` stored under the path,
* which is not a subtype of the requested type `Vault`.
*/
let vault <- account.storage.load<@Vault>(from: /storage/otherCounter)
/* The storage still stores a `Counter` resource under the path `\/storage\/otherCounter`. */
/* Save the string "Hello, World" in storage
under the path `\/storage\/helloWorldMessage`. */
account.storage.save(
"Hello, world!",
to: /storage/helloWorldMessage
)
/* Copy the stored message from storage.
*
* After the copy, the storage still stores the string under the path.
* Unlike `load`, `copy` does not remove the object from storage.
*/
let message = account.storage.copy<String>(from: /storage/helloWorldMessage)
/* Create a new instance of the resource type `Vault`
* and save it in the storage of the account.
*/
account.storage.save(
<-createEmptyVault(),
to: /storage/vault
)
/* Invalid: Cannot copy a resource, as this would allow arbitrary duplication. */
let vault <- account.storage.copy<@Vault>(from: /storage/vault)
/* Create a reference to the object stored under path `\/storage\/counter`,
* typed as `&Counter`.
*
* `counterRef` has type `&Counter?` and is a valid reference, i.e. non-`nil`,
* because the borrow succeeded:
*
* There is an object stored under path `\/storage\/otherCounter`
* and it has type `Counter`, so it can be borrowed as `&Counter`
*/
let counterRef = account.storage.borrow<&Counter>(from: /storage/otherCounter)
counterRef?.count /* is `42` */
/* Create a reference to the object stored under path `/storage/otherCounter`,
* typed as `&{HasCount}`.
*
* `hasCountRef` is non-`nil`, as there is an object stored under path `\/storage\/otherCounter`,
* and the stored value of type `Counter` conforms to the requested type `{HasCount}`:
* the type `Counter` implements the intersection type's interface `HasCount`
*/
let hasCountRef = account.storage.borrow<&{HasCount}>(from: /storage/otherCounter)
/* Create a reference to the object stored under path `\/storage\/otherCounter`,
* typed as `&{SomethingElse}`.
*
* `otherRef` is `nil`, as there is an object stored under path `\/storage\/otherCounter`,
* but the stored value of type `Counter` does not conform to the requested type `{SomethingElse}`:
* the type `Counter` does not implement the intersection type's interface `SomethingElse`
*/
let otherRef = account.storage.borrow<&{SomethingElse}>(from: /storage/otherCounter)
/* Create a reference to the object stored under path `\/storage\/nonExistent`,
* typed as `&{HasCount}`.
*
* `nonExistentRef` is `nil`, as there is nothing stored under path `\/storage\/nonExistent`
*/
let nonExistentRef = account.storage.borrow<&{HasCount}>(from: /storage/nonExistent)
Iterating over stored objects
次の関数は、アカウントのストレージを繰り返し処理することができます。
fun forEachPublic(_ function: fun(PublicPath, Type): Bool)
fun forEachStored(_ function: fun(StoragePath, Type): Bool)
この関数は、特定のドメインに保存されているすべてのオブジェクトを順に処理し、各保存されたオブジェクトに対してコールバック関数を呼び出し、保存されたオブジェクトのパスと実行時型を渡します。
コールバック関数から返されるBool
値によって、繰り返し処理を継続するかどうかを決定します。コールバック関数がtrue
を返した場合、繰り返し処理は次の保存オブジェクトに進みます。コールバック関数がfalse
を返した場合、繰り返し関数は停止します。オブジェクトが繰り返し処理される順序は不定であり、パスがストレージから追加または削除された場合の動作も同様です。
⚠ WARNING
反復関数は、壊れたオブジェクトをスキップします。
オブジェクトは、格納された値に関連する無効な型によって壊れる可能性があります。例えば、格納されたオブジェクトのスマートコントラクトに構文エラーや意味エラーがある場合などです。
⚠ WARNING
反復の順序は不定です。特定の動作を当てにしてはいけません。
このような操作の後でプログラムが反復処理を継続すると、プログラムが中断します。
このようなエラーを回避するには、反復処理中にオブジェクトをストレージに保存したり、ストレージからオブジェクトを読み込んだりしないようにします。このような操作を行う場合は、反復処理のコールバックからfalse
を返して、以下のように、変更処理の後に反復処理を終了させます。
account.storage.save(1, to: /storage/foo1)
account.storage.save(2, to: /storage/foo2)
account.storage.save(3, to: /storage/foo3)
account.storage.save("qux", to: /storage/foo4)
account.storage.forEachStored(fun (path: StoragePath, type: Type): Bool {
if type == Type<String>() {
/* Save a value to storage while iterating */
account.storage.save("bar", to: /storage/foo5)
/* Returning false here ends iteration after storage is modified,
preventing the program from aborting */
return false
}
return true
})
Storage limit
アカウントのストレージは、そのストレージ容量によって制限されます。
アカウントの使用ストレージは、アカウントが保存するすべてのデータのサイズの合計(MB)です。アカウントのストレージ容量は、アカウントのメインFLOWトークン保管庫に保存されているFLOWの量から算出される値です。
すべてのトランザクションの終了時に、使用されたストレージがストレージ容量と比較されます。トランザクションに関与するすべてのアカウントにおいて、アカウントの使用ストレージがストレージ容量よりも大きい場合、そのトランザクションは失敗します。
アカウントは、storage.used
フィールドを通じて使用ストレージを公開し、storage.capacity
フィールドを通じてストレージ容量を公開します。
これらのフィールドは現在の値を表します。
/* Query the storage used before saving an object */
let storageUsedBefore = account.storage.used
/* Save a resource into storage */
account.storage.save(
<-create Counter(count: 123),
to: /storage/counter
)
/* Query the storage used again after saving */
let storageUsedAfter = account.storage.used
let storageUsedChanged = storageUsedAfter > storageUsedBefore // is true
翻訳元
Flow BlockchainのCadence version1.0ドキュメント (Storage)