====== 共変_反変 ======
Kotlinの場合
不変(Array)...同じ型でなければならない。(そもそもlistは不変ではない)
共変(out)...上位の型に下位の型を入れることが出来る。
設定といっても初期値(val)として。
取り出す(参照)ときには上位の型として取り出す。
反変(in)...下位の定義を上位の定義を設定できる。
設定とはvar変数に値をいれること。
参照するときは上位の型として参照する。
===== 不変 =====
fun main() {
// --- 不変 ... 同じ型でなければならない ---
// listは不変ではない
val intList = listOf(1, 2, 3)
val anyList: List = intList
// 配列は不変
val intArray = Array(3,{index -> index})
// val anyArray:Array = intArray // 方が違うのでコンパイルエラー
===== 共変(out) =====
valとして変更しない、参照用(out)として値を設定する
上位のAny型に、下位のint型を設定しているが、Any型として参照しかしない(out)ので安全。
// --- 共変(out) ... 広い定義に狭い定義のものを参照用に入れることが出来る(val) ---
// --- 提供するだけ 戻り値として広い定義を使用できる
val intArray2 = Array(3,{index -> index})
val anyArray2:Array = intArray2 // outがないとコンパイルエラー
val tmp2 = anyArray2[2] // outとしてはAny?型となる
if(tmp2 is Any?){
println("temp2 is Any")
}else{
println("temp2 is not Any")
}
↓
temp2 is Any
===== 反変(in) =====
varの値を変更する。
下位のHuman型の配列に、上位のAnimal型の配列を設定しているが、Animal型としてしか参照しないので安全。
// --- 反変 ...
val intArray3 = Array(3,{index -> index*3})
var anyArray3:Array = intArray3
anyArray3.forEach { println("anyArray3=${it}")}
// --- 反変2 クラス これはできて当たり前
open class Animal(val name:String){
open fun Cry(){println("${name}!!")}
}
class Human(name:String):Animal(name){
override fun Cry(){println("I'm${name}")}
}
val animal:Animal = Human("Takeshi") // クラスは共変
animal.Cry()
// --- 反変2 クラス配列 これが本当の反変
val humanArray:Array = Array(1, {i -> Animal("Gray")}) // Human型にAnimalが入る
// val animal2:Human = humanArray[0] as Human // Human型だとコンパイルでエラーとなる
// animal2.Cry() // エラーとなる
val animal3:Animal = humanArray[0] as Animal // Animal型だと取り出せる。
animal3.Cry() // Animal型として使える
}
===== Listの場合 =====
listはそもそも不変ではない。
val intList = listOf(1,2,3)
val strList= listOf("a","b","c")
val anyList:List = intList + strList
anyList.forEach {
println(it)
}
↓
1
2
3
a
b
c
val anyList2 = listOf("a","b","c")
// val intList2:List = anyList2 コンパイルエラー