Kotlin の ジェネリクスと変性

# なぜ変性が必要か

* 変性には3種類ある。
* 不変(invariance) 、共変(covariance) と 反変（contravariance)
* 以下にそれぞれ説明する。

## 不変

```kotlin

fun main(args: Array<String>){

    var fooStr: Foo<String> = object: Foo<String>{  //...(1)
        override fun f(): String {
            return "foo"
        }
    }

    var fooAny: Foo<Any> = object: Foo<Any>{  //...(2)
        override fun f(): Any {
            return "foo"
        }
    }

    fooAny = fooStr   //...(3) 

    var anyVar: Any = fooAny.f()   //...(4)
}

//Foo のメソッド は　型R を返すのみで、引数には使わない。
interface Foo<R>{
    fun f(): R
}

```

* 上記のコードは (3) でコンパイルエラーとなる。
* しかし、仮にコンパイルが通ったとしたら、 (4) はどうなるか。
* (4) で問題が起きることはない。 Foo<R> のメソッド f は R型を返すのみなので、 Any に String を格納することは問題ない。
* つまり、 Any のサブタイプが String であるように、 Foo\<String\> を Foo\<Any\> のサブタイプとみなしても矛盾は起こらない。
* Any が Stringの親　であるように、
*  Foo\<Any\> は Foo\<String\>の親　とみなせる。
* にも関わらず、(3)でコンパイルエラーとなるのは変性が不変だからである。
* それを解決するのが共変となる。
* 以下に、共変を用いたコードを示す。

## 共変
```kotlin

fun main(args: Array<String>){

    var fooStr: Foo<String> = object: Foo<String>{  //...(1)
        override fun f(): String {
            return "foo"
        }
    }

    var fooAny: Foo<out Any> = object: Foo<Any>{  //...(2) Foo(out Any) に書き換えた。
        override fun f(): Any {
            return "foo"
        }
    }

    fooAny = fooStr   //...(3) 

    var anyVar: Any = fooAny.f()   //...(4)
}

//Foo のメソッド は　型R を返すのみで、引数には使わない。
interface Foo<R>{
    fun f(): R
}
```

* 上記のコードは、(2) を Foo\<out Any\> に書き換えた。
* これは、Any を戻り値のみに使用することを明記することで、 (3) の実行を可能にしている。
* これが共変である。
* 共変とは
*  Any が Stringの親　であるように、
*  Foo\<Any\> は Foo\<String\>の親　となる
*  この親子関係が共に変わると考えるとわかりやすい。

## 反変

```kotlin


fun main(args: Array<String>){

    var barStr: Bar<String> = object: Bar<String>{  //...(1)
        override fun f(x: String){
            println(x)
        }
    }

    var barAny: Bar<Any> = object: Bar<Any{  //...(2)
        override fun f(x: Any){
            println(x)
        }
    }

    barStr = barAny   //...(3) 

    barStr.f("bar")   //...(4)
}

//Bar のメソッド は　型 T を引数にとるが、戻り値には使用しない。
interface Bar<T>{
    fun f(x: T)
}
```

* 上記のコードは (3) でコンパイルエラーとなる。
* しかし、仮にコンパイルが通ったとしたら、　（４）はどうなるか。
* (4) で問題が起きることはない。
* (3) の時点で、 barStr に Bar\<Any\> のインスタンスが入っているが、そのメソッドf はAny の引数を受け取ることができるので、 (4)で "bar" を受け取ることができる。
* この性質は、
* Any は String の親であるが、
* Bar\<Any\> は Bar\<String\> の子であると解釈できる。
* にも関わらず、コンパイルエラーとなるのは、上記のコードの変性が不変だからである。
* それを解決するのが、反変である。
* 以下に半変を用いたコードを示す。

```kotlin

fun main(args: Array<String>){

    var barStr: Bar<in String> = object: Bar<String>{  //...(1)
        override fun f(x: String){
            println(x)
        }
    }

    var barAny: Bar<Any> = object: Bar<Any{  //...(2)
        override fun f(x: Any){
            println(x)
        }
    }

    barStr = barAny   //...(3) 

    barStr.f("bar")   //...(4)
}

//Bar のメソッド は　型 T を引数にとるが、戻り値には使用しない。
interface Bar<T>{
    fun f(x: T)
}
```

* 上記のコードは (1) を Bar\<in String\> に書き換えた。
* これは、Barのメソッド内で String を引数のみに利用することを明記することで、（３）の実行を可能にしている。
* これによって、
* Any は String の親
* Bar\<Any\> を Bar\<String\> の子の様に扱うことができる。
* Bar<T> の親子関係が、共変とは逆であり、これを反変と呼ぶ。

## インタフェース定義時に変性を指定する

* これまでの説明では、main 関数内で変性のキーワード(in, out) を指定していたが、interface 内で書くと便利である。
* 以下の様に、変性のキーワードを interface内で指定すると良い。

```

fun main(args: Array<String>){
    //　中略
}

//Foo のメソッド は　型R を返すのみで、引数には使わない。
interface Foo<out R>{
    fun f(): R
}

//Bar のメソッド は　型 T を引数にとるが、戻り値には使用しない。
interface Bar<in T>{
    fun f(x: T)
}
```