2016-04-12 5 views
19

Listの最初または最後の項目ではないすべての項目を返す関数を記述したい(経由点)。この関数は汎用のList<*>を入力として取得します。Kotlin:リストキャストの操作方法:チェックされていないキャスト:kotlin.collections.List <Kotlin.Any?> to kotlin.colletions.List <Waypoint>

未確認出演:kotlin.collections

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>を鋳造し、私は警告を受ける:リストの要素の型Waypointである場合、結果は返されるべきです。リスト とkotlin.colletions.List

私はそれ以外の方法を実装する方法を見つけることができません。この警告なしでこの機能を実装する正しい方法は何ですか?

答えて

52

一般的なケースでは、実行時に汎用パラメータを確認する方法はありません(特別な場合にのみList<T>の項目をチェックするなど)。そのためジェネリックパラメータを別のジェネリックパラメータでキャストするとキャストがvariance boundsの中になければ警告を発しなさい。

しかし、さまざまなソリューションがあります。

  • あなたはタイプをチェックして、あなたはキャストが安全であることをかなり確信しています。それで、suppress the warning@Suppress("UNCHECKED_CAST")とすることができます。

    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 } 
    

    アイテムタイプをチェックして、渡されたタイプのアイテムのリストを返す

    @Suppress("UNCHECKED_CAST") 
    val waypointList = list as? List<Waypoint> ?: return null 
    
  • 使用.filterIsInstance<T>()機能、これにより、必要なタイプの新しいリストが作成され(内部のチェックされていないキャストは回避されます)、わずかなオーバーヘッドが発生しますが、同時に反復処理の時間が節約されます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 
    
+2

グレート回答!私はlist.filterIsInstance ()ソリューションを選択します。なぜなら、これは最もクリーンなソリューションだと思うからです。 – lukle

+3

['filterIsInstance'](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/filter-is-instance.html)を使用し、元のリストに異なるタイプの要素が含まれているあなたのコードはそれらを静かにフィルタリングします。時にはこれがあなたが望むものですが、時にはIllegalStateExceptionまたは同様のものが投げられることがあります。 'inline fun Iterable <*> .mapAsInstance()= map {it.apply {これはRです}}をR}' – mfulton26

+0

にすることに注意してください。 '.apply'はラムダの戻り値を返しません、それは受信オブジェクトを返します。オプションにnullを返す場合は、おそらく '.takeIf'を使用します。 – bj0

2

汎用クラスの場合、実行時に型情報が消去されるため、キャストをチェックできません。しかし、リスト内のすべてのオブジェクトがWaypointであることを確認すると、警告を@Suppress("UNCHECKED_CAST")で抑制することができます。

このような警告を避けるには、Waypointに変換可能なオブジェクトのListを渡す必要があります。 *を使用していて、このリストに入力リストとしてアクセスしようとすると、常にキャストが必要になり、このキャストはチェックされません。

関連する問題