gpt4 book ai didi

generics - 如何以类型安全的方式从通用列表中检索项目

转载 作者:行者123 更新时间:2023-12-02 03:01:34 25 4
gpt4 key购买 nike

我想将项目放入通用容器中,但以类型安全的方式检索它们。添加时,容器将使用序列号标记每个项目。我尝试在 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)}
}

最佳答案

你问:

Is there a way to use type information in a function argument to define the type of the return value?

是的。您可以使用 generic functionsreified type parameters来完成这个。您使用通用函数让它工作。有关使用具体化参数的示例,请参见下面的示例。

讨论

不幸的是 filter 只返回原始类型的项目:

fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T>

这意味着您必须使用过滤并返回不同类型的方法。尝试使用诸如 filterIsInstance 之类的方法很诱人。做这项工作。不幸的是,在这种情况下,类型是 Ref<T> . filterIsInstance失败,因为 T 变成了删除类型,导致所有项都被返回。这意味着您必须定义自己的版本,该版本基于成员变量类型而不是整个类型进行测试。我的偏好是使它成为列表而不是容器的函数,如下所示:

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<T : Item> (val id: Int, val item: T)

inline fun <reified R: Item> List<Ref<*>>.filter(predicate: (Ref<*>) -> Boolean): List<Ref<R>> {
val result = ArrayList<Ref<R>>()
@Suppress("UNCHECKED_CAST")
for(item in this) if (predicate(item)) result.add(item as Ref<R>)
return result
}


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))

// to retrieve pens in a type safe manner
fun pens() = items.filter<Pen> { it.item is Pen }
}


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"))

println("[${container.pens()}]")
}

这种方法允许您以最小的努力在代码中的任何位置执行类似的过滤,并且它是 Kotlin 惯用的。

内联函数是 filterIsInstance 的 Kotlin 源代码的变形.不幸的是,未经检查的转换是不可避免的。

关于generics - 如何以类型安全的方式从通用列表中检索项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45710060/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com