宣言側変性
inとoutを学びます
「宣言側変性」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。
変性の問題
List<String>はList<Any>の一種でしょうか?答えは場合によって異なります。変性とは、型パラメーター同士の関係に応じて、ジェネリック型同士がどのような関係になるかを表すものです。Kotlinでは、これをoutとinで表現します。
デフォルトでは不変
デフォルトでは、ジェネリクスは不変です。StringがAnyのサブタイプであっても、Box<String>はBox<Any>ではありません。これにより、安全でない操作を防げます。
class Box<T>(val value: T)
fun main() {
val strBox = Box("hi")
// val anyBox: Box<Any> = strBox // would not compile
println(strBox.value)
}out による共変
型パラメーターにoutを付けると共変になり、Producer<String>はProducer<Any>のサブタイプになります。この型パラメーターは出力位置(戻り値の型)にのみ現れます。
class Producer<out T>(private val item: T) {
fun produce(): T = item
}
fun main() {
val strProducer: Producer<String> = Producer("hello")
val anyProducer: Producer<Any> = strProducer
println(anyProducer.produce())
}out が安全な理由
クラスがTを生成(返却)するだけで、決して受け取らない場合、Producer<String>をProducer<Any>として扱っても安全です。返されるすべてのStringは、同時にAnyでもあるためです。
標準ライブラリでの out
Kotlinの読み取り専用List<out E>は共変です。そのため、List<String>をList<Any>が期待される場所で使用できます。
fun printAll(items: List<Any>) {
items.forEach { println(it) }
}
fun main() {
val names: List<String> = listOf("Ann", "Bob")
printAll(names)
}in による反変
型パラメーターにinを付けると反変になり、Consumer<Any>はConsumer<String>のサブタイプになります。この型パラメーターは入力位置(パラメーター)にのみ現れます。
class Consumer<in T> {
fun consume(item: T) {
println("Consumed $item")
}
}
fun main() {
val anyConsumer: Consumer<Any> = Consumer()
val strConsumer: Consumer<String> = anyConsumer
strConsumer.consume("hi")
}in が安全な理由
Anyを受け取れるコンシューマーは、当然Stringも受け取れます。そのため、Consumer<Any>はConsumer<String>が必要な場所で使えます。
PECSという覚え方
Producer Extends, Consumer Superと覚えるか、Kotlinの用語では、生成する側(出力)にはout、消費する側(入力)にはinを使うと覚えてください。Tを出力するだけの型にはoutを、Tを入力するだけの型にはinを使います。
in と out の組み合わせ
型パラメーターを入力と出力の両方に使う場合(可変リストなど)は、不変のままにする必要があります。Function型には両方の性質があり、パラメーターはin、戻り値はoutです。
fun main() {
val f: (Number) -> Int = { it.toInt() }
val g: (Int) -> Number = f
println(g(3.0.let { Number::class; 5 }))
}宣言側変性は1か所で指定する
宣言側変性は、クラス自体にinまたはoutを付けて1度だけ宣言します。その後クラスを使うたびに変性が自動的に適用されます。使用箇所ごとにワイルドカードを繰り返すJavaとは異なります。
in と out の選び方
次のように考えてください。このクラスはTを生成するだけならout、Tを消費するだけならin、両方なら不変のままにします。役割に合った修飾子を選ぶことで、ジェネリック型を柔軟かつ安全にできます。
確認問題
out 修飾子は何を示しますか?
まとめ
ジェネリクスはデフォルトでは不変です。型が値を生成するだけなら共変を表すoutを、値を消費するだけなら反変を表すinを使います。生成する側にはout、消費する側にはinと覚えてください。次は、型プロジェクションを使って使用箇所で変性を適用します。
よくある質問
「宣言側変性」レッスンは無料ですか?
はい。「宣言側変性」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。
「宣言側変性」で何を学びますか?
inとoutを学びます ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Kotlin Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「宣言側変性」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このKotlin Academyレッスンでコードを書いて実行できますか?
はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。