以前のリビジョンの文書です
Kotlinの場合
不変(Array)…同じ型でなければならない。(そもそもlistは不変ではない)
共変(out)…上位の型に下位の型を入れることが出来る。
設定といっても初期値(val)として。
取り出す(参照)ときには上位の型として取り出す。
反変(in)…下位の定義を上位の定義を設定できる。
設定とはvar変数に値をいれること。
参照するときは上位の型として参照する。
fun main() { // --- 不変 ... 同じ型でなければならない --- // listは不変ではない val intList = listOf<Int>(1, 2, 3) val anyList: List<Any> = intList // 配列は不変 val intArray = Array<Int>(3,{index -> index}) // val anyArray:Array<Any> = intArray // 方が違うのでコンパイルエラー
valとして変更しない、参照用(out)として値を設定する
上位のAny型に、下位のint型を設定しているが、Any型として参照しかしない(out)ので安全。
// --- 共変(out) ... 広い定義に狭い定義のものを参照用に入れることが出来る(val) --- // --- 提供するだけ 戻り値として広い定義を使用できる val intArray2 = Array<Int>(3,{index -> index}) val anyArray2:Array<out Any?> = 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
varの値を変更する。
下位のHuman型の配列に、上位のAnimal型の配列を設定しているが、Animal型としてしか参照しないので安全。
// --- 反変 ... val intArray3 = Array<Int>(3,{index -> index*3}) var anyArray3:Array<in Int> = 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<in Human> = 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型として使える }