1. taketo1024

    No comment

    taketo1024
Changes in body
Source | HTML | Preview
@@ -1,45 +1,47 @@
-社内の「Scala 勉強会」で **Phantom Type (幽霊型)** という厨二心をくすぐる感じのデザインパターンを教えてもらったので、同じことを Swift でもやってみました。インスタンスの状態を変数ではなく **型パラメータ** として持つことで、状態チェックを実行時ではなく **コンパイル時** に行えるという優れものです。
+社内の「Scala 勉強会」で **Phantom Type (幽霊型)** という厨二心をくすぐる感じのデザインパターンを教えてもらったので、同じことを Swift でもやってみました。
+
+インスタンスの状態を変数ではなく **型パラメータ** として持つことで、状態チェックを実行時ではなく **コンパイル時** に行えるという優れものです。
```
class Status{}
class NotReady: Status{}
class Ready: Status{}
class Something<T: Status> {
static func createInstance() -> Something<NotReady> {
return Something<NotReady>()
}
func readify() -> Something<Ready> {
return Something<Ready>()
}
}
extension Something where Status: Ready {
func shout() {
print("phantom types are awesome!")
}
}
```
`Status` は `NotReady`, `Ready` をサブクラスに持つだけの空クラス(これが幽霊型)で、`Something` は `Status` 型の型パラメータ `T` を持っています。`Something` には `where Status: Ready` という **型パラメータ制約付きの拡張** によって、`shout()` という関数を追加しています。
`createInstance()` で`Something<NotReady>` インスタンスが作られ、`readify()` を呼ぶと新たに `Something<Ready>` インスタンスが作られます。そうして作られた `T` が `Ready` のインスタンスに対してのみ `shout()` を呼ぶコードが書けるのです。
やってみましょう:
```
let s = Something.createInstance()
s.shout() // error: 'NotReady' is not a subtype of 'Ready'
```
ちゃんと **コンパイルエラー** が出ました!
一方で `readify()` を呼ぶと…
```
let s = Something.createInstance()
s.readify().shout() // phantom types are awesome!
```
エラーもなく、ちゃんと実行もできました!
**Phantom Type** カッコイイですね :trollface::+1: