最初のアイテムでも最後のアイテムでもない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>
の項目をチェックするなど)実行時にジェネリックパラメーターをチェックする方法がないため、ジェネリックタイプを別のジェネリックパラメーターを持つ別のキャストにキャストすると、警告が発生しますキャストは variance bounds 内にあります。
ただし、さまざまなソリューションがあります。
タイプを確認し、キャストが安全であると確信しています。その場合、@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
ジェネリッククラスの場合、型情報は実行時に消去されるため、キャストをチェックできません。ただし、リスト内のすべてのオブジェクトがWaypoint
sであることを確認するため、@Suppress("UNCHECKED_CAST")
を使用して警告を抑制することができます。
このような警告を回避するには、List
に変換可能なオブジェクトのWaypoint
を渡す必要があります。 *
を使用しているが、このリストに型付きリストとしてアクセスしようとすると、常にキャストが必要になり、このキャストはオフになります。
@hotkeyの答えを改善するために、ここに私の解決策があります:
val waypointList = list.filterIsInstance<Waypoint>().takeIf { it.size == list.size }
これにより、すべてのアイテムをキャストできる場合はList<Waypoint>
、そうでない場合はnullが得られます。
Serializable to Listオブジェクトのチェックに使用する場合、@ hotkey answerに少し変化を加えました。
@Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> Serializable.checkSerializableIsListOf() =
if (this is List<*> && this.all { it is T })
this as List<T>
else null