Run-time Types

[Previous << Core Events](https://qiita.com/flowcadence/items/5e0aea26c0ce24fab7e9)
[Next >> Built-in Functions](https://qiita.com/flowcadence/items/e1528810ca4a72c8f521)

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

型は実行時に表現できます。型値を作成するには、コンストラクタ関数 `Type<T>()` を使用します。この関数は、静的型を型引数として受け取ります。
これは、例えばSwiftの`T.self`、Kotlinの`T::class`/`KClass<T>`、Javaの`T.class`/`Class<T>`に似ています。
例えば、実行時に型 `Int` を表現するには：

```ruby
let intType: Type = Type<Int>()
```
これは、組み込み型とユーザー定義型の両方で機能します。例えば、リソースの型値を取得するには：

```ruby
resource Collectible {}

let collectibleType = Type<@Collectible>()

/* `collectibleType` has type `Type` */
```
型の値は比較可能です。
```ruby
Type<Int>() == Type<Int>()

Type<Int>() != Type<String>()
```
`view fun isSubtype(of: Type): Bool` メソッドを使用すると、実行時に型の値を比較することができます。

```ruby
Type<Int>().isSubtype(of: Type<Int>())
/* true */

Type<Int>().isSubtype(of: Type<String>())
/* false */

Type<Int>().isSubtype(of: Type<Int?>())
/* true */
```

実行時の型の完全修飾型識別子を取得するには、`let identifier: String`フィールドを使用します。
```ruby
let type = Type<Int>()
type.identifier  /* is "Int" */
```
```ruby
/* in account 0x1 */

struct Test {}

let type = Type<Test>()
type.identifier  /* is "A.0000000000000001.Test" */
```

<h1 id="Getting-the-Type-from-a-Value">Getting the Type from a Value</h1>

`view fun getType(): Type`というメソッドを使用すると、値の実行時型を取得できます。

```ruby
let something = "hello"

let type: Type = something.getType()
/* `type` is `Type<String>()` */
```

このメソッドは、静的型ではなく、オブジェクトの具体的な実行時の型を返します。
```ruby
/* Declare a variable named `something` that has the *static* type `AnyResource`
 * and has a resource of type `Collectible`
 */
let something: @AnyResource <- create Collectible()

/* The resource's concrete run-time type is `Collectible` */
let type: Type = something.getType()
/* `type` is `Type<@Collectible>()` */
```

<h1 id="Constructing-a-Run-time-Type">Constructing a Run-time Type</h1>

実行時の型は、組み込みのコンストラクタ関数を使用して型識別子文字列から構築することもできます。
```ruby
view fun CompositeType(_ identifier: String): Type?
view fun InterfaceType(_ identifier: String): Type?
view fun IntersectionType(types: [String]): Type?
```
型識別子（または`IntersectionType`の場合はインターフェースの識別子のリスト）が与えられた場合、これらの関数は名義型を検索し、その実行時等価値を生成します。与えられた識別子がいずれの型にも一致しない場合、または（`IntersectionType`の場合）与えられた識別子の組み合わせが静的に型チェックを通らない場合、これらの関数は`nil`を生成します。
```ruby
struct Test: I {}
struct interface I {}
let type: Type = CompositeType("A.0000000000000001.Test")
/* `type` is `Type<Test>` */

let type2: Type = IntersectionType(
    restrictions: ["A.0000000000000001.I"]
)
/* `type2` is `Type<{I}>` */
```

その他の組み込み関数は、他の実行型から複合型を構築します。
```ruby
view fun OptionalType(_ type: Type): Type
view fun VariableSizedArrayType(_ type: Type): Type
view fun ConstantSizedArrayType(type: Type, size: Int): Type
view fun FunctionType(parameters: [Type], return: Type): Type
/* returns `nil` if `key` is not valid dictionary key type */
view fun DictionaryType(key: Type, value: Type): Type?
/* returns `nil` if `type` is not a reference type */
view fun CapabilityType(_ type: Type): Type?
view fun ReferenceType(entitlements: [String], type: Type): Type?
```

<h1 id="Asserting-the-Type-of-a-Value">Asserting the Type of a Value</h1>

`view fun isInstance(_ type: Type): Bool` メソッドは、値が特定の型であるかどうかを、具体的な実行時型を使用して、サブタイピングルール(原文: subtyping rules)を考慮しながら確認するために使用できます。

```ruby
/* Declare a variable named `collectible` that has the *static* type `Collectible`
 * and has a resource of type `Collectible`
 */
let collectible: @Collectible <- create Collectible()

/* The resource is an instance of type `Collectible`,
 * because the concrete run-time type is `Collectible`
 */
collectible.isInstance(Type<@Collectible>())
/* is `true` */

/* The resource is an instance of type `AnyResource`,
 * because the concrete run-time type `Collectible` is a subtype of `AnyResource`
 */
collectible.isInstance(Type<@AnyResource>())
/* is `true` */

/* The resource is *not* an instance of type `String`,
 * because the concrete run-time type `Collectible` is *not* a subtype of `String`
 */
collectible.isInstance(Type<String>())
/* is `false` */
```

オブジェクトの具体的な実行時型が使用され、静的型ではないことに注意してください。
```ruby
/* Declare a variable named `something` that has the *static* type `AnyResource`
 * and has a resource of type `Collectible`
 */
let something: @AnyResource <- create Collectible()

/* The resource is an instance of type `Collectible`,
 * because the concrete run-time type is `Collectible`
 */
something.isInstance(Type<@Collectible>())
/* is `true` */

/* The resource is an instance of type `AnyResource`,
 * because the concrete run-time type `Collectible` is a subtype of `AnyResource`
 */
something.isInstance(Type<@AnyResource>())
/* is `true` */

/* The resource is *not* an instance of type `String`,
 * because the concrete run-time type `Collectible` is *not* a subtype of `String`
 */
something.isInstance(Type<String>())
/* is `false` */
```
例えば、これによりマーケットプレイス販売リソースを実装することができます。

```ruby
access(all)
resource SimpleSale {

    /** The resource for sale.
     *  Once the resource is sold, the field becomes `nil`.
     */
    access(all)
    var resourceForSale: @AnyResource?

    /** The price that is wanted for the purchase of the resource. */
    access(all)
    let priceForResource: UFix64

    /** The type of currency that is required for the purchase. */
    access(all)
    let requiredCurrency: Type
    access(all)
    let paymentReceiver: Capability<&{FungibleToken.Receiver}>

    /** `paymentReceiver` is the capability that will be borrowed
     *  once a valid purchase is made.
     *  It is expected to target a resource that allows depositing the paid amount
     *  (a vault which has the type in `requiredCurrency`).
     */
    init(
        resourceForSale: @AnyResource,
        priceForResource: UFix64,
        requiredCurrency: Type,
        paymentReceiver: Capability<&{FungibleToken.Receiver}>
    ) {
        self.resourceForSale <- resourceForSale
        self.priceForResource = priceForResource
        self.requiredCurrency = requiredCurrency
        self.paymentReceiver = paymentReceiver
    }

    /** buyObject allows purchasing the resource for sale by providing
     *  the required funds.
     *  If the purchase succeeds, the resource for sale is returned.
     *  If the purchase fails, the program aborts.
     */
    access(all)
    fun buyObject(with funds: @FungibleToken.Vault): @AnyResource {
        pre {
            /* Ensure the resource is still up for sale */
            self.resourceForSale != nil: "The resource has already been sold"
            /* Ensure the paid funds have the right amount */
            funds.balance >= self.priceForResource: "Payment has insufficient amount"
            /* Ensure the paid currency is correct */
            funds.isInstance(self.requiredCurrency): "Incorrect payment currency"
        }

        /* Transfer the paid funds to the payment receiver
         * by borrowing the payment receiver capability of this sale resource
         * and depositing the payment into it */

        let receiver = self.paymentReceiver.borrow()
            ?? panic("failed to borrow payment receiver capability")

        receiver.deposit(from: <-funds)
        let resourceForSale <- self.resourceForSale <- nil
        return <-resourceForSale
    }
}
```

翻訳元

https://cadence-lang.org/docs/language/run-time-types

***
<b>[Previous << Core Events](https://qiita.com/flowcadence/items/5e0aea26c0ce24fab7e9)
</b>

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

<b>[Next >> Built-in Functions](https://qiita.com/flowcadence/items/e1528810ca4a72c8f521)</b>