Kotlin: リストキャストの操作方法: チェックなしキャスト: kotlin.collections.List kotlin.colletions.List へ 質問する

Kotlin: リストキャストの操作方法: チェックなしキャスト: kotlin.collections.List kotlin.colletions.List へ 質問する

List最初または最後の項目 (経由点) 以外の、内のすべての項目を返す関数を記述したいと思います。関数はList<*>、入力としてジェネリックを受け取ります。結果は、リストの要素が の型である場合にのみ返されますWaypoint

fun getViaPoints(list: List<*>): List<Waypoint>? {

    list.forEach { if(it !is Waypoint ) return null }

    val waypointList = list as? List<Waypoint> ?: return null

    return waypointList.filter{ waypointList.indexOf(it) != 0 && waypointList.indexOf(it) != waypointList.lastIndex}
}

List<*>を にキャストするとList<Waypoint>、次の警告が表示されます:

チェックなしのキャスト: kotlin.collections.List から kotlin.colletions.List へ

それ以外の方法で実装する方法がわかりません。この警告を出さずにこの関数を実装する正しい方法は何ですか?

ベストアンサー1

Kotlinでは、一般的なケースでは実行時にジェネリックパラメータをチェックする方法はありません(List<T>特別なケースである a の項目をチェックするだけなど)。そのため、ジェネリック型を別のジェネリックパラメータを持つ別の型にキャストすると、キャストが範囲内にない限り警告が発生します。分散境界

ただし、さまざまな解決策があります。

  • 型を確認し、キャストが安全であることを確信しました。それを踏まえて、警告を抑制する@Suppress("UNCHECKED_CAST")

    @Suppress("UNCHECKED_CAST")
    val waypointList = list as? List<Waypoint> ?: return null
    
  • 使用.filterIsInstance<T>()関数は、アイテムの種類をチェックし、渡された種類のアイテムを含むリストを返します。

    val waypointList: List<Waypoint> = list.filterIsInstance<Waypoint>()
    
    if (waypointList.size != list.size)
        return null
    

    または、同じことを 1 つのステートメントで記述します。

    val waypointList = list.filterIsInstance<Waypoint>()
        .apply { if (size != list.size) return null }
    

    これにより、目的の型の新しいリストが作成され (内部の未チェックのキャストが回避されます)、若干のオーバーヘッドが発生しますが、同時に、反復処理listと型のチェック (インラインlist.foreach { ... }) が不要になるため、目立たなくなります。

  • 型をチェックし、型が正しい場合は同じリストを返すユーティリティ関数を記述し、その中にキャスト (コンパイラの観点からはまだチェックされていない) をカプセル化します。

    @Suppress("UNCHECKED_CAST")
    inline fun <reified T : Any> List<*>.checkItemsAre() =
            if (all { it is T })
                this as List<T>
            else null
    

    使用法:

    val waypointList = list.checkItemsAre<Waypoint>() ?: return null
    

おすすめ記事