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