Resources

[Previous << Composite Types](https://qiita.com/flowcadence/items/d15aeb14b6bbddd9e717)
[Next >> Access control](https://qiita.com/flowcadence/items/572df270135946f5290e)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#cadenceの言語仕様を学ぶ

リソース(Resource)は、同時に**1箇所**の場所にしか存在できない型です。

リソースは、`create` キーワードを使用して作成する必要があります。（インスタンス化します）

関数の終了時には、リソース（変数、定数、パラメータ）がその関数のスコープ内に存在する場合、必ずリソースは**ストレージに移動もしくは破棄する必要があります**。

変数に初期値として渡す場合や異なる変数に割り当てる場合、関数に引数として渡す場合、関数の戻り値とする場合に、リソースは**移動し**ます。

リソースは、`destroy` キーワードを使用して明示的に破棄することができます。

リソースが移動されると、移動前にリソースを参照していた定数または変数は無値(無効)になります。無値(無効な)リソースは、使用することができません。

リソース型の使用法と動作を明確にするために、変数または定数の宣言、パラメータ、および戻り値の型のアノテーションで、接頭辞 `@`を付ける必要があります。

<h1 id="the-move-operator">The Move Operator</h1>

リソースの移動を明示的に行うには、移動演算子`<-`を使用する必要があります。リソースが変数の初期値である場合、異なる変数に移動される場合、引数として関数に移動される場合、関数から返される場合です。

```ruby
/* Declare a resource named `SomeResource`, with a variable integer field. */
access(all)
resource SomeResource {
    
    access(all)
    var value: Int

    init(value: Int) {
        self.value = value
    }
}

/* Declare a constant with value of resource type `SomeResource`. */
let a: @SomeResource <- create SomeResource(value: 0)

/* *Move* the resource value to a new constant. */
let b <- a

/* Invalid: Cannot use constant `a` anymore as the resource that it referred to
 * was moved to constant `b`.
 */
a.value

/* Constant `b` owns the resource. */
b.value // equals 0

/* Declare a function which accepts a resource.
 *
 * The parameter has a resource type, so the type annotation must be prefixed with `@`.
 */
access(all)
fun use(resource: @SomeResource) {
    /* ... */
}

/* Call function `use` and move the resource into it. */
use(resource: <-b)

/* Invalid: Cannot use constant `b` anymore as the resource
 * it referred to was moved into function `use`.
 */
b.value
```
リソースオブジェクトがスコープ外に出て動的に失われることはありません。Cadenceのプログラムは明示的にそれを破棄するか、別のコンテキストに移動する必要があります。

```ruby
panic("something went wrong: ...")
```

<h1 id="assert">assert</h1>

```ruby
{
    /* Declare another, unrelated value of resource type `SomeResource`. */
    let c <- create SomeResource(value: 10)

    /* Invalid: `c` is not used before the end of the scope, but must be.
       It cannot be lost. */
}
```
```ruby
/* Declare another, unrelated value of resource type `SomeResource`. */
let d <- create SomeResource(value: 20)

/* Destroy the resource referred to by constant `d`. */
destroy d

/* Invalid: Cannot use constant `d` anymore as the resource
 * it referred to was destroyed.
 */
d.value
```
型がリソース型であり、リソースに関連するルールに従わなければならないことを明確にするために、すべての型アノテーションに接頭辞@を付ける必要があります。例えば、変数宣言、パラメータ、または関数の戻り値の型にです。
```ruby
/* Declare a constant with an explicit type annotation.
 *
 * The constant has a resource type, so the type annotation must be prefixed with `@`.
 */
let someResource: @SomeResource <- create SomeResource(value: 5)

/* Declare a function which consumes a resource and destroys it.
 *
 * The parameter has a resource type, so the type annotation must be prefixed with `@`.
 */
access(all)
fun use(resource: @SomeResource) {
    destroy resource
}

/* Declare a function which returns a resource.
 *
 * The return type is a resource type, so the type annotation must be prefixed with `@`.
 * The return statement must also use the `<-` operator to make it explicit the resource is moved.
 */
access(all)
fun get(): @SomeResource {
    let newResource <- create SomeResource()
    return <-newResource
}
```
リソース必ず一度だけ使用しなければなりません。(関数の引数に２回渡せません)
```ruby
/* Declare a function which consumes a resource but does not use it.
 * This function is invalid, because it would cause a loss of the resource.
 */
access(all)
fun forgetToUse(resource: @SomeResource) {
    /* Invalid: The resource parameter `resource` is not used, but must be. */
}
```
```ruby
/* Declare a constant named `res` which has the resource type `SomeResource`. */
let res <- create SomeResource()

/* Call the function `use` and move the resource `res` into it. */
use(resource: <-res)

/* Invalid: The resource constant `res` cannot be used again,
 * as it was moved in the previous function call.
 */
use(resource: <-res)

/* Invalid: The resource constant `res` cannot be used again,
 * as it was moved in the previous function call.
 */
res.value
```
```ruby
/* Declare a function which has a resource parameter.
 * This function is invalid, because it does not always use the resource parameter,
 * which would cause a loss of the resource.
 */
access(all)
fun sometimesDestroy(resource: @SomeResource, destroyResource: Bool) {
    if destroyResource {
        destroy resource
    }
    /* Invalid: The resource parameter `resource` is not always used, but must be.
     * The destroy statement is not always executed, so at the end of this function
     * it might have been destroyed or not. */
}
```
```ruby
/* Declare a function which has a resource parameter.
 * This function is valid, as it always uses the resource parameter,
 * and does not cause a loss of the resource.
 */
access(all)
fun alwaysUse(resource: @SomeResource, destroyResource: Bool) {
    if destroyResource {
        destroy resource
    } else {
        use(resource: <-resource)
    }
    /* At the end of the function the resource parameter was definitely used:
       It was either destroyed or moved in the call of function `use`. */
}
```
```ruby
/* Declare a function which has a resource parameter.
 * This function is invalid, because it does not always use the resource parameter,
 * which would cause a loss of the resource.
 */
access(all)
fun returnBeforeDestroy(move: Bool) {
    let res <- create SomeResource(value: 1)
    if move {
        use(resource: <-res)
        return
    } else {
        /* Invalid: When this function returns here, the resource variable
           `res` was not used, but must be. */
        return
    }
    /* Invalid: the resource variable `res` was potentially moved in the
     * previous if-statement, and both branches definitely return,
     * so this statement is unreachable. */
    destroy res
}
```

<h1 id="Resource-Variables">Resource Variables</h1>

リソース変数に値を代入することはできません。これは、変数の現在のリソース値が失われることになるからです。

代わりに、スワップ文（`<->`）またはシフト文（`<- target <-`）を使用して、リソース変数を別のリソースに置き換えます。

```ruby
access(all)
resource R {}

var x <- create R()
var y <- create R()

/* Invalid: Cannot assign to resource variable `x`,
 * as its current resource would be lost
 */
x <- y

/* Instead, use a swap statement. */
var replacement <- create R()
x <-> replacement
/* `x` is the new resource.
   `replacement` is the old resource. */

/* Or use the shift statement (`<- target <-`)
 * This statement moves the resource out of `x` and into `oldX`,
 * and at the same time assigns `x` with the new value on the right-hand side. */
let oldX <- x <- create R()
 /* oldX still needs to be explicitly handled after this statement */
destroy oldX
```


<h1 id="nested-resources">Nested Resources</h1>

複合型(配列やディクショナリなど)のフィールドは、リソース型を持つと通常と異なる動作をします。

フィールドのリソース内のフィールドにアクセスしたり、関数を呼び出すことは可能ですが、リソースをそのフィールドから移動することは許可されていません。その代わり、リソースを別のリソースと置き換えるために、スワップステートメントを利用できます。
```ruby
let child <- create Child(name: "Child 1")
child.name  /* is "Child 1" */

let parent <- create Parent(name: "Parent", child: <-child)
parent.child.name  /* is "Child 1" */

/* Invalid: Cannot move resource out of variable resource field. */
let childAgain <- parent.child

/* Instead, use a swap statement. */
var otherChild <- create Child(name: "Child 2")
parent.child <-> otherChild
/* `parent.child` is the second child, Child 2.
   `otherChild` is the first child, Child 1. */
```
リソースがネストされたリソースを持つ状態で`destroy`ステートメントで破棄すると、すべてのネストされたリソースも破棄されます。
```ruby
/* Declare a resource with resource fields */
access(all)
resource Parent {
    var child1: @Child
    var child2: @Child
    init(child1: @Child, child2: @Child) {
        self.child1 <- child1
        self.child2 <- child2
    }
}
```
入れ子になったリソースが破棄される順序は決定論的(deterministic)ですが、特定されておらず、開発者によって影響を与えることはできません。例えば、この例では、`Parent` が破棄されると、`child1`および`child2`フィールドも特定されていない順序で破棄されます。

Cadence の以前のバージョンでは、リソースが破棄されたときに任意のコードを実行する特別な`destroy`関数を定義することが可能でしたが、今はもう利用できません。

<h1 id="Destroy-Events">Destroy Events</h1>

リソースの破棄時に実行する任意のコードを指定することはできませんが、リソースが破棄された際に自動的に発行される特別な[イベント](https://qiita.com/flowcadence/items/07a1cd2e6ca15272900f)を指定することは可能です。このイベントには予約名`ResourceDestroyed`が割り当てられており、特別な構文を使用します。

```ruby
resource R {
    event ResourceDestroyed(id: UInt64 = self.id) 

    let id: UInt64

    init(_ id: UInt64) {
        self.id = id
    }
}
```
このように定義された型`R`の値が破棄されると、特別な
`R.ResourceDestroyed`イベントが発行されます。 `ResourceDestroyed`の定義で使用されている特別な構文は、全てのイベントパラメータに関連付いた値を指定します。

この場合、`R.ResourceDestroyed`イベントの`id`フィールドは、リソースRが破棄される直前に保持していた`id`フィールドの値です。 一般的に、いくつかの`ResourceDestroyed`イベントは次のように定義される：

 ```ruby
 event ResourceDestroyed(field1: T1 = e1, field2: T2 = e2, ...)
 ```

イベントの`field1`の値は、リソースを破棄する前に`e1`を評価した結果となります。イベントの`field2`の値は、リソースを破棄する前に`e2`を評価した結果となります。以下同様です。当然のことながら、`e1`および`e2`もそれぞれ、`T1`および`T2`型の式でなければなりません。

これらのイベントが実行時に失敗することなく確実に発せられることを保証するために、それらの定義で使用できる型と式の種類には制限があります。

一般的には、フィールドの値を宣言する式は、`self`（[アタッチメント](https://qiita.com/flowcadence/items/4b41229869c45bc8a4df)の場合は`base`）のメンバー、selfのインデックス付きアクセス、またはリテラルのみです。イベントのフィールドの型は、数値型、`String`、`Boolean`、`Address`、`Path`に限定されます。


<h1 id="resources-in-closures">Resources in Closures</h1>

リソースはクロージャで捕捉できません。重複が発生する可能性があるためです。
```ruby
resource R {}

/* Invalid: Declare a function which returns a closure which refers to
 * the resource parameter `resource`. Each call to the returned function
 * would return the resource, which should not be possible.
 */
fun makeCloner(resource: @R): fun(): @R {
    return fun (): @R {
        return <-resource
    }
}

let test = makeCloner(resource: <-create R())
```

<h1 id="Resources-in-Arrays-and-Dictionaries">Resources in Arrays and Dictionaries</h1>

配列とディクショナリは、リソースを含む場合、異なる動作をします。配列にインデックスを指定して特定のインデックスの要素を読み取ったり、そこに値を代入したり、ディクショナリにインデックスを指定して特定のキーの値を読み取ったり、キーに値を設定したりすることは**できません**。

代わりに、swapステートメント（`<->`）またはshiftステートメント（`<- target <-`）を使用して、リソースを別の変数に置き換えます。
```ruby
resource R {}

/* Declare a constant for an array of resources.
 * Create two resources and move them into the array.
 * `resources` has type `@[R]`
 */
let resources <- [
    <-create R(),
    <-create R()
]

/* Invalid: Reading an element from a resource array is not allowed. */
let firstResource <- resources[0]

/* Invalid: Setting an element in a resource array is not allowed,
 * as it would result in the loss of the current value.
 */
resources[0] <- create R()

/* Instead, when attempting to either read an element or update an element
 * in a resource array, use a swap statement with a variable to replace
 * the accessed element.
 */
var res <- create R()
resources[0] <-> res
/* `resources[0]` now contains the new resource.
   `res` now contains the old resource. */

/* Use the shift statement to move the new resource into
   the array at the same time that the old resource is being moved out */
let oldRes <- resources[0] <- create R()
 /* The old object still needs to be handled */
destroy oldRes
```
ディクショナリについても同様です。
```ruby
/* Declare a constant for a dictionary of resources.
 * Create two resources and move them into the dictionary.
 * `resources` has type `@{String: R}`
 */
let resources <- {
    "r1": <-create R(),
    "r2": <-create R()
}

/* Invalid: Reading an element from a resource dictionary is not allowed.
 * It's not obvious that an access like this would have to remove
 * the key from the dictionary.
 */
let firstResource <- resources["r1"]

/* Instead, make the removal explicit by using the `remove` function. */
let firstResource <- resources.remove(key: "r1")

/* Invalid: Setting an element in a resource dictionary is not allowed,
 * as it would result in the loss of the current value.
 */
resources["r1"] <- create R()

/* Instead, when attempting to either read an element or update an element
 * in a resource dictionary, use a swap statement with a variable to replace
 * the accessed element.
 *
 * The result of a dictionary read is optional, as the given key might not
 * exist in the dictionary.
 * The types on both sides of the swap operator must be the same,
 * so also declare the variable as an optional.
 */
var res: @R? <- create R()
resources["r1"] <-> res
/* `resources["r1"]` now contains the new resource.
   `res` now contains the old resource. */

/* Use the shift statement to move the new resource into
   the dictionary at the same time that the old resource is being moved out */
let oldRes <- resources["r2"] <- create R()
/* The old object still needs to be handled */
destroy oldRes
```
リソースを配列やディクショナリに複数回移動することはできません。重複が発生するためです。
```ruby
let resource <- create R()

/* Invalid: The resource variable `resource` can only be moved into the array once. */
let resources <- [
    <-resource,
    <-resource
]
```
```ruby
let resource <- create R()

/* Invalid: The resource variable `resource` can only be moved into the dictionary once. */
let resources <- {
    "res1": <-resource,
    "res2": <-resource
}
```
リソースの配列やディクショナリは破棄できます。
```ruby
let resources <- [
    <-create R(),
    <-create R()
]
destroy resources
```
```ruby
let resources <- {
    "r1": <-create R(),
    "r2": <-create R()
}
destroy resources
```
配列の関数である`append`、`insert`、`remove`は、リソース以外の配列と同様に動作します。

```ruby
let resources <- [<-create R()]
/* `resources.length` is `1` */

resources.append(<-create R())
/* `resources.length` is `2` */

let first <- resource.remove(at: 0)
/* `resources.length` is `1` */
destroy first

resources.insert(at: 0, <-create R())
/* `resources.length` is `2` */

/* Invalid: The statement ignores the result of the call to `remove`,
   which would result in a loss. */
resource.remove(at: 0)

destroy resources
```
配列関数`contains`は利用できません。これは不可能だからです。(リソースが`contains`関数に渡されれば、それは定義上、配列には含まれないからです。）

配列関数`concat`は利用できません。リソースが重複してしまうからです。

`insert`や`remove`などのディクショナリ関数は、リソース以外のディクショナリの場合と同様に動作します。
```ruby
let resources <- {"r1": <-create R()}
/* `resources.length` is `1` */

let first <- resource.remove(key: "r1")
/* `resources.length` is `0` */
destroy first

let old <- resources.insert(key: "r1", <-create R())
/* `old` is nil, as there was no value for the key "r1"
   `resources.length` is `1` */

let old2 <- resources.insert(key: "r1", <-create R())
/* `old2` is the old value for the key "r1"
   `resources.length` is `1` */

destroy old
destroy old2
destroy resources
```

<h1 id="Resource-Identifier">Resource Identifier</h1>

リソースには暗黙的な一意の識別子が関連付けられており、各リソースにあらかじめ宣言されたpublicフィールド`let uuid: UInt64`によって実装されています。

この識別子は、リソースが作成された際に、リソースの初期化子(init関数)が呼び出される前に自動的に設定され（つまり、識別子は初期化子(init関数)で使用できます）、リソースが破棄された後でも一意であり続けます。つまり、2つのリソースが同じ識別子を持つことはありません。
```ruby
/* Declare a resource without any fields. */
resource R {}

/* Create two resources */
let r1 <- create R()
let r2 <- create R()

/* Get each resource's unique identifier */
let id1 = r1.uuid
let id2 = r2.uuid

/* Destroy the first resource */
destroy r1

/* Create a third resource */
let r3 <- create R()

let id3 = r3.uuid

id1 != id2  // true
id2 != id3  // true
id3 != id1  // true
```
:::note warn 
⚠ WARNING
識別子の生成方法の詳細は、実装の詳細です。
Cadenceプログラムにおける特定の動作を前提としたり、それに依存したりしないでください。
:::
<h1 id="Resource-Owner">Resource Owner</h1>

リソースには、暗黙的なフィールド`let owner: &Account?`があります。リソースが[アカウントのストレージ](https://qiita.com/flowcadence/items/129d58ae7cb962056c6c)に保存されている場合、このフィールドにアカウントのpublicアクセス可能部分が含まれます。それ以外の場合、このフィールドには`nil`が入りります。

リソースがアカウント外のストレージからアカウントのストレージに移動した場合、あるアカウントのストレージから別のアカウントのストレージに移動した場合、およびアカウントのストレージから移動した場合、このフィールドの値は変更されます。

翻訳元

https://cadence-lang.org/docs/language/resources

***
<b>[Previous << Composite Types](https://qiita.com/flowcadence/items/d15aeb14b6bbddd9e717)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (Resources)

<b>[Next >> Access control](https://qiita.com/flowcadence/items/572df270135946f5290e)</b>