Kotlin:如何处理列表转换:未选中Cast:kotlin.collections.List <kotlin.any?> to kotlin.colletions.List <waypoint>

时间:2016-04-12 09:41:26

标签: list generics casting kotlin

我想编写一个函数,它返回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>时,我会收到警告:

  

未选中Cast:kotlin.collections.List   到kotlin.colletions.List

我无法找到实现它的方法。没有这个警告,实现这个功能的正确方法是什么?

5 个答案:

答案 0 :(得分:117)

在Kotlin中,在一般情况下无法检查运行时的泛型参数(例如只检查List<T>的项目,这只是一种特殊情况),因此转换为泛型类型对于具有不同通用参数的另一个参数,除非演员位于variance bounds内,否则将发出警告。

然而,有不同的解决方案:

  • 您已经检查了类型,并且您确信演员阵容是安全的。鉴于此,您可suppress the warning使用@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
    

    或在同一声明中相同:

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

    这将创建一个所需类型的新列表(从而避免未经检查的强制转换),引入一点开销,但同时它可以避免迭代list并检查类型(在{中{1}}行),所以它不会引人注意。

  • 编写一个检查类型的实用程序函数,如果类型正确则返回相同的列表,从而将转换(从编译器的角度来看仍未选中)封装在其中:

    list.foreach { ... }

    用法:

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

答案 1 :(得分:3)

如果是泛型类,则无法检查强制转换,因为在运行时会删除类型信息。但是你检查列表中的所有对象都是Waypoint,这样你就可以用@Suppress("UNCHECKED_CAST")来抑制警告。

要避免此类警告,您必须传递List可转换为Waypoint的对象。当您使用*但尝试将此列表作为输入列表进行访问时,您将始终需要进行投射,并且此投射将被取消选中。

答案 2 :(得分:0)

要改善@hotkey的答案,这是我的解决方案:

args.port = args.port || 8100;
args.target = args.target || "ie";//prior to this instead of "ie" it was "chrome" 

如果可以投射所有项目,这会给您val waypointList = list.filterIsInstance<Waypoint>().takeIf { it.size == list.size } ,否则为null。

答案 3 :(得分:0)

当用于检查可序列化为列出对象时,我对@hotkey回答做了一些改动:

    @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

答案 4 :(得分:-1)

代替

myGenericList.filter { it is AbstractRobotTurn } as List<AbstractRobotTurn>

我喜欢做

myGenericList.filter { it is AbstractRobotTurn }.map { it as AbstractRobotTurn }

不确定性能如何,但至少没有警告。