Kotlin:如何使用List转换:未选中Cast:kotlin.collections.List <Kotlin.Any?>转换为kotlin.colletions.List <Waypoint>

我想写一个函数,返回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

否则,我无法想出一个办法来实施它。 没有这个警告,什么是正确的方式来实现这个功能?

在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 

    或在一个声明中相同:

     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所以你可以用@Suppress("UNCHECKED_CAST")来压制警告。

为了避免这样的警告,您必须传递一个可转换为Waypoint的对象List 。 当你使用*但试图访问这个列表作为一个打字清单,你总是需要一个强制转换,这个强制转换将被取消选中。