Generics 如何以类型安全的方式从泛型列表中检索项
我希望将项目放入通用容器中,但以类型安全的方式检索它们。添加时,容器将用序列号标记每个项目。我试图在Kotlin中实现这一点,但在Generics 如何以类型安全的方式从泛型列表中检索项,generics,kotlin,Generics,Kotlin,我希望将项目放入通用容器中,但以类型安全的方式检索它们。添加时,容器将用序列号标记每个项目。我试图在Kotlin中实现这一点,但在pens()方法中遇到了问题。有没有办法在函数参数中使用类型信息来定义返回值的类型 import java.util.concurrent.atomic.AtomicInteger import kotlin.reflect.KClass interface Item data class Pen(val name: String) : Item data clas
pens()
方法中遇到了问题。有没有办法在函数参数中使用类型信息来定义返回值的类型
import java.util.concurrent.atomic.AtomicInteger
import kotlin.reflect.KClass
interface Item
data class Pen(val name: String) : Item
data class Eraser(val name: String) : Item
data class Ref<out T : Item> (val id: Int, val item: T)
class Container<T: Item> {
private val seq = AtomicInteger(0)
private val items: MutableList<Ref<T>> = mutableListOf()
fun add(item: T) = items.add(Ref(seq.incrementAndGet(), item))
fun filter(cls: KClass<*>) : List<Ref<T>> = items.filter{cls.isInstance(it.item)}.toList()
// to retrieve pens in a type safe manner
// Type mismatch required: List<Ref<Pen>> found: List<Ref<T>>
fun pens(): List<Ref<Pen>> = filter(Pen::class)
}
fun main(args: Array<String>) {
val container = Container<Item>()
container.add(Pen("Pen-1"))
container.add(Pen("Pen-2"))
container.add(Eraser("Eraser-3"))
container.add(Eraser("Eraser-4"))
// the filter method works
container.filter(Pen::class).forEach{println(it)}
}
导入java.util.concurrent.AtomicInteger
导入kotlin.reflect.KClass
接口项
数据类笔(val名称:字符串):项
数据类擦除器(val名称:字符串):项
数据类参考(val id:Int,val项:T)
类容器{
private val seq=AtomicInteger(0)
私有val项:MutableList=mutableListOf()
趣味添加(item:T)=items.add(参考(seq.incrementAndGet(),item))
趣味过滤器(cls:KClass):List=items.filter{cls.isInstance(it.item)}.toList()
//以类型安全的方式检索笔
//需要类型不匹配:找到列表:列表
趣味笔():列表=过滤器(笔::类)
}
趣味主线(args:Array){
val container=container()
容器。添加(Pen(“Pen-1”))
容器。添加(Pen(“Pen-2”))
容器。添加(橡皮擦(“橡皮擦-3”))
容器。添加(橡皮擦(“橡皮擦-4”))
//过滤方法有效
container.filter(Pen::class).forEach{println(it)}
}
您的过滤器
方法返回类型列表
,而笔
方法返回类型列表
。因为您将容器
声明为容器
,所以过滤器类型实际上是列表
。不能将列表
设置为等于列表
您可以制作笔
返回列表
(这可能会破坏您正在寻找的类型安全性)。或者,对于笔
,将带有映射的列表转换为列表
。例如
fun pens(): List<Ref<Pen>> = filter(Pen::class).map {
it as Ref<Pen> )
}
fun pens():List=filter(笔::类).map{
作为参考)
}
根据,上面使用的as
操作符是一个“不安全”的cast操作符。这是因为it.item
可以是任何item
或item
的子类型。如果it.item
不是Pen
,将引发异常。但是,由于您只对Pen
项进行筛选,因此它永远不会抛出异常 我通过将泛型参数移动到方法并执行一个不安全的强制转换来实现它,该转换在过滤器操作之后应该总是成功的。这是完整的代码
import java.util.concurrent.atomic.AtomicInteger
import kotlin.reflect.KClass
interface Item
data class Pen(val name: String) : Item
data class Eraser(val name: String) : Item
data class Ref<out T : Item> (val id: Int, val item: T)
class Container {
private val seq = AtomicInteger(0)
private val items: MutableList<Ref<Item>> = mutableListOf()
fun <T: Item> add(item: T) = items.add(Ref(seq.incrementAndGet(), item))
private fun <T: Item> filter(cls: KClass<T>) : List<Ref<T>> =
items.filter{cls.isInstance(it.item)}.map{it as Ref<T>}
fun pens(): List<Ref<Pen>> = filter(Pen::class)
fun erasers(): List<Ref<Eraser>> = filter(Eraser::class)
}
fun main(args: Array<String>) {
val container = Container()
container.add(Pen("Pen-1"))
container.add(Eraser("Eraser-2"))
container.add(Pen("Pen-3"))
container.add(Eraser("Eraser-4"))
container.pens().forEach{println(it)}
container.erasers().forEach{println(it)}
}
导入java.util.concurrent.AtomicInteger
导入kotlin.reflect.KClass
接口项
数据类笔(val名称:字符串):项
数据类擦除器(val名称:字符串):项
数据类参考(val id:Int,val项:T)
类容器{
private val seq=AtomicInteger(0)
私有val项:MutableList=mutableListOf()
趣味添加(item:T)=items.add(参考(seq.incrementAndGet(),item))
私人娱乐过滤器(cls:KClass):列表=
items.filter{cls.isInstance(it.item)}.map{it as Ref}
趣味笔():列表=过滤器(笔::类)
有趣的橡皮擦():列表=过滤器(橡皮擦::类)
}
趣味主线(args:Array){
val container=container()
容器。添加(Pen(“Pen-1”))
容器。添加(橡皮擦(“橡皮擦-2”))
容器。添加(Pen(“Pen-3”))
容器。添加(橡皮擦(“橡皮擦-4”))
container.pens().forEach{println(it)}
container.橡皮擦().forEach{println(it)}
}
您问:
有没有办法在函数参数中使用类型信息来定义返回值的类型
import java.util.concurrent.atomic.AtomicInteger
import kotlin.reflect.KClass
interface Item
data class Pen(val name: String) : Item
data class Eraser(val name: String) : Item
data class Ref<out T : Item> (val id: Int, val item: T)
class Container<T: Item> {
private val seq = AtomicInteger(0)
private val items: MutableList<Ref<T>> = mutableListOf()
fun add(item: T) = items.add(Ref(seq.incrementAndGet(), item))
fun filter(cls: KClass<*>) : List<Ref<T>> = items.filter{cls.isInstance(it.item)}.toList()
// to retrieve pens in a type safe manner
// Type mismatch required: List<Ref<Pen>> found: List<Ref<T>>
fun pens(): List<Ref<Pen>> = filter(Pen::class)
}
fun main(args: Array<String>) {
val container = Container<Item>()
container.add(Pen("Pen-1"))
container.add(Pen("Pen-2"))
container.add(Eraser("Eraser-3"))
container.add(Eraser("Eraser-4"))
// the filter method works
container.filter(Pen::class).forEach{println(it)}
}
对。您可以使用和来完成此任务。您可以使用泛型函数使其工作。有关使用具体化参数的示例,请参见下面的示例
讨论
遗憾的是,仅返回原始类型的项目:
fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T>
这种方法只需很少的努力,就可以在代码中的任何地方进行类似的过滤,这就是惯用的Kotlin
内联函数是的Kotlin源的变形。不幸的是,未经检查的强制转换是不可避免的。过滤器会生成一个Ref列表。有没有办法将Ref强制转换为Ref,而不是创建Ref的新副本?