Star Projectionと*の使いどころ
不明なジェネリック型にStar Projectionを適用し、その制限を理解します。
「Star Projectionと*の使いどころ」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。
スター投影とは
スター投影(*)は、「型引数が不明なジェネリック型」を表すKotlinの方法です。Javaのraw型や、境界のないワイルドカード<?>に相当する安全な仕組みです。
fun printList(list: List<*>) {
for (item in list) println(item)
}
fun main() {
printList(listOf(1, 2, 3))
printList(listOf("a", "b"))
printList(listOf(true, 42, "mixed"))
}スター投影された型からの読み取り
List<*>から要素を読み取ると、Any?として扱えます。実際の型が不明なため、要素を追加することはできません。
fun process(list: List<*>) {
val first: Any? = list.firstOrNull()
println("First: $first, Size: ${list.size}")
// list.add("x") // compile error: can't write to List<*>
}
fun main() {
process(listOf(10, 20, 30))
}スター投影とout Anyの違い
List<*>とList<out Any?>は同等です。スター投影は、上限境界を持つ共変投影の省略記法です。
fun sumStars(list: List<*>): Int = list.size
fun sumOut(list: List<out Any?>): Int = list.size
fun main() {
val l = listOf(1, "two", true)
println(sumStars(l)) // 3
println(sumOut(l)) // 3
}関数パラメーターでのスター投影
ジェネリック型の任意のバリエーションを受け入れつつ、Tを知る必要のないメソッドだけを呼び出す場合は、関数シグネチャーで*を使用します。
fun containerInfo(map: Map<*, *>): String {
return "keys=${map.keys.size}, values=${map.values.size}"
}
fun main() {
val m = mapOf(1 to "one", 2 to "two")
println(containerInfo(m))
}MutableListでのスター投影
MutableList<*>では、Any?として読み取れますが、まったく書き込めません。コンパイラーによって防止されます。
fun clearFirstElement(list: MutableList<*>) {
if (list.isNotEmpty()) {
list.removeAt(0) // OK: remove by index doesn't need T
// list.add("x") // Error: can't write unknown type
}
}
fun main() {
val m = mutableListOf(1, 2, 3)
clearFirstElement(m)
println(m) // [2, 3]
}スター投影を使用したクラス
実行時にジェネリッククラスの型を確認するときは、型引数が消去されるためスター投影を使用します。
fun isListOfSomething(obj: Any): Boolean {
return obj is List<*> // OK with star
// obj is List<String> // Warning: cannot check erased type
}
fun main() {
println(isListOfSomething(listOf(1, 2))) // true
println(isListOfSomething("not a list")) // false
}複数のスター型パラメーター
不明な型のPairやMapを扱う場合、関数に複数のスター投影されたパラメーターを指定できます。
fun describeMap(map: Map<*, *>) {
map.forEach { (k, v) ->
println("${k?.javaClass?.simpleName} -> ${v?.javaClass?.simpleName}")
}
}
fun main() {
describeMap(mapOf("key" to 42, 1 to true))
}スター投影を使わない場合
コレクションへの書き込みが必要な場合や、代わりに境界付き型パラメーターを使える場合は、スター投影を避けてください。境界付き型パラメーターのほうが多くの情報を提供できます。
// Bad: loses type information
fun addToStar(list: MutableList<*>, item: Any?) {
// list.add(item) // compile error
}
// Better: use bounded type parameter
fun <T : Any> addTyped(list: MutableList<T>, item: T) {
list.add(item)
}
fun main() {
val l = mutableListOf("a")
addTyped(l, "b")
println(l)
}型チェックとキャストでのスター投影
スター投影を使ってジェネリッククラスに対するinstanceofチェックを行い、その後、実際の処理のために特定の型へキャストします。
fun handleResponse(response: Any) {
if (response is List<*>) {
val list = response as List<*>
println("List with ${list.size} elements")
val first = list.firstOrNull()
if (first is String) println("First string: $first")
}
}
fun main() {
handleResponse(listOf("hello", "world"))
handleResponse(42)
}実践:ジェネリックイベントディスパッチャー
任意のHandler<*>を受け入れながら、型付きイベントを安全にディスパッチするディスパッチャーです。
interface Handler<in T> { fun handle(event: T) }
class LogHandler : Handler<Any> {
override fun handle(event: Any) = println("Event: $event")
}
fun dispatch(handler: Handler<*>, event: Any) {
@Suppress("UNCHECKED_CAST")
(handler as Handler<Any>).handle(event)
}
fun main() {
dispatch(LogHandler(), "click")
dispatch(LogHandler(), 42)
}reifiedコンテキストでのスター投影
スター投影は、KClass<*>を使って実行時に型を調べるリフレクションやシリアライズのコードで特によく使用されます。
fun printClassName(klass: kotlin.reflect.KClass<*>) {
println(klass.simpleName)
}
fun main() {
printClassName(String::class) // String
printClassName(List::class) // List
printClassName(Int::class) // Int
}クイックチェック
List<*>から読み取ると、どの型になりますか。
まとめ
スター投影(*)は、読み取り専用アクセスで任意のジェネリック型のバリエーションを受け入れます。型チェック、ジェネリックユーティリティ、リフレクションに使用します。コレクションへの書き込みが必要な場合や、境界付き型パラメーターのほうが高い型安全性を提供できる場合は避けてください。
よくある質問
「Star Projectionと*の使いどころ」レッスンは無料ですか?
はい。「Star Projectionと*の使いどころ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。
「Star Projectionと*の使いどころ」で何を学びますか?
不明なジェネリック型にStar Projectionを適用し、その制限を理解します。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Kotlin Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「Star Projectionと*の使いどころ」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このKotlin Academyレッスンでコードを書いて実行できますか?
はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- whereによるジェネリック関数と型制約
- 宣言側変性:inとout
- Star Projectionと*の使いどころ
- 型消去とreified型パラメータ