Generics kotlin泛型:无法推断类型参数
我需要Kotlin中的集合只包含实现给定接口的元素 例如:包含动物集合的地图:Generics kotlin泛型:无法推断类型参数,generics,kotlin,Generics,Kotlin,我需要Kotlin中的集合只包含实现给定接口的元素 例如:包含动物集合的地图: interface Animal { val name: String } data class Monkey(override val name: String): Animal data class Snake(override val name: String): Animal 通过阅读文档和博客等问题,我编写了以下代码,其中使用了关键字中的泛型: class Test { private val d
interface Animal { val name: String }
data class Monkey(override val name: String): Animal
data class Snake(override val name: String): Animal
通过阅读文档和博客等问题,我编写了以下代码,其中使用了关键字中的泛型:
class Test {
private val data = HashMap<String, ArrayList<in Animal>>()
init {
data.put("Monkeys", arrayListOf(Monkey("Kong"), Monkey("Cheetah")))
data.put("Snakes", arrayListOf(Snake("Monthy"), Snake("Kaa")))
}
}
类测试{
private val data=HashMap()
初始化{
数据。put(“猴子”)、arrayListOf(猴子(“香港”)、猴子(“猎豹”))
data.put(“蛇类”)、arrayListOf(蛇类(“Monthy”)、蛇类(“Kaa”))
}
}
现在,我想在测试类中添加一个读取“数据”内容的方法,例如将其打印到控制台:
fun printAll() {
data.forEach { collectionName: String, animals: ArrayList<in Animal> ->
println(collectionName)
animals.forEach { animal: Animal ->
println("\t$animal")
}
}
}
fun printAll(){
data.forEach{collectionName:String,animals:ArrayList->
println(集合名称)
animals.forEach{动物:动物->
println(“\t$animal”)
}
}
}
如果这样做,则会出现编译错误:
Error:(27, 21) Kotlin: Type inference failed: Cannot infer type parameter T in inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit
None of the following substitutions
receiver: Iterable<Any?> arguments: ((Any?) -> Unit)
receiver: Iterable<Animal> arguments: ((Animal) -> Unit)
can be applied to
receiver: kotlin.collections.ArrayList<in Animal> /* = java.util.ArrayList<in Animal> */ arguments: ((Animal) -> Unit)
错误:(27,21)Kotlin:类型推断失败:无法推断内联fun Iterable中的类型参数T。forEach(操作:(T)->Unit):Unit
以下替代品均不适用
接收者:Iterable参数:((任何?->单位)
接收者:Iterable参数:((动物)->单位)
适用于
接收方:kotlin.collections.ArrayList/*=java.util.ArrayList*/参数:((动物)->单位)
我的解决方案是强迫我的动物进入ArrayList:
。。。
(作为ArrayList的动物)。forEach{动物:动物->
println(“\t$animal”)
}
...
但我不确定这是否是编写此类代码的最佳方式。
有没有更好的方法告诉Kotlin我想在泛型中为生产者和消费者使用子类型?我想您不需要
数据类型中的in
关键字
在这里使用意味着您希望那些ArrayList
的类型参数至少与Animal
一样通用,这意味着ArrayList
实际上也可以用Animal
的超类型参数化:您甚至可以将ArrayList
放入映射中,这清楚地表明,期望列表只包含Animal
s是不安全的
考虑删除
关键字中的,只留下ArrayList
(甚至是列表
,它是只读列表的接口):
private val data=HashMap()
初始化{
数据。put(“猴子”)、列表(猴子(“香港”)、猴子(“猎豹”))
数据。输入(“蛇”,列表(蛇(“蒙蒂”),蛇(“Kaa”))
}
趣味打印全部(){
data.forEach{collectionName:字符串,动物:列表->
println(集合名称)
animals.forEach{动物:动物->
println(“\t$animal”)
}
}
}
事实上,切换到不可变的列表
s还有一个额外的好处:这意味着现在可以将listOf(Monkey(“Kong”)、Monkey(“Cheetah”)
视为列表
而不是列表
。这个解决方案也适用于可变列表界面,如果我需要一个函数来检索列表以对其进行修改,它会很方便。更常见的是在类签名中看到in
/out
通用关键字来定义类是“消费”还是“生产”该类型。您可以在此处阅读这些关键字:
...
(animals as ArrayList<out Animal>).forEach { animal: Animal ->
println("\t$animal")
}
...
private val data = HashMap<String, List<Animal>>()
init {
data.put("Monkeys", listOf(Monkey("Kong"), Monkey("Cheetah")))
data.put("Snakes", listOf(Snake("Monthy"), Snake("Kaa")))
}
fun printAll() {
data.forEach { collectionName: String, animals: List<Animal> ->
println(collectionName)
animals.forEach { animal: Animal ->
println("\t$animal")
}
}
}