1. ホーム
  2. list

[解決済み] Kotlin: Listのキャストの扱い方。チェックなし キャスト: kotlin.collections.List<Kotlin.Any?> to kotlin.colletions.List<Waypoint>

2022-05-12 19:56:38

質問

の中のすべての項目を返す関数を書きたい。 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に変更しました。

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

どのように解決するのですか?

Kotlinでは、一般的な場合、実行時にジェネリックパラメータをチェックする方法はありません(例えば、単に List<T> の項目をチェックするようなもので、これは特殊なケースです)、そのため、ジェネリック型を異なるジェネリックパラメータを持つ別の型にキャストすると、そのキャストが 分散境界 .

しかし、別の解決策もあります。

  • 型をチェックし、キャストが安全であることを確信している。それを考えると、あなたは 警告を抑制する @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