Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 如何以类型安全的方式从泛型列表中检索项_Generics_Kotlin - Fatal编程技术网

Generics 如何以类型安全的方式从泛型列表中检索项

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

我希望将项目放入通用容器中,但以类型安全的方式检索它们。添加时,容器将用序列号标记每个项目。我试图在Kotlin中实现这一点,但在
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的新副本?