我最近在科特林尝试了以下方法。我的想法是,我将收到一个Item(AmericanItem例如)extends 作为输入BaseItem。我试图为这些项目中的每个项目使用不同的解析器,这是示例代码
abstract class BaseItem
class AmericanItem : BaseItem()
class EuropeanItem : BaseItem()
interface ItemParser<T : BaseItem> {
fun parse(item: T)
}
class AmericanItemParser : ItemParser<AmericanItem> {
override fun parse(item: AmericanItem) {
println("AmericanItemParser")
}
}
class EuropeanItemParser : ItemParser<EuropeanItem> {
override fun parse(item: EuropeanItem) {
println("parsing EuropeanItem")
}
}
fun main(args: Array<String>) {
val hashMap = HashMap<Class<out BaseItem>, ItemParser<*>>()
hashMap.put(AmericanItem::class.java, EuropeanItemParser())
hashMap.put(EuropeanItem::class.java, AmericanItemParser())
val inputItem = EuropeanItem()
val foundParser = hashMap[inputItem.javaClass]
foundParser?.parse(inputItem)
}
Run Code Online (Sandbox Code Playgroud)
我的问题在最后一行,当我尝试调用解析器时,出现以下编译错误
Out-projected type 'ItemParser<*>?' prohibits the use of 'public abstract fun parse(item: T): kotlin.Unit defined in ItemParser'
Run Code Online (Sandbox Code Playgroud)
我在这里做错了什么?
您在Map和的声明之间创建了冲突ItemParser。该地图可以包含的任何后代BaseItem,但ItemParser设计成每个后代只能对一个的后裔BaseItem。因此,对于给定的实例,ItemParser它必须接受它可以识别的某些内容,在这里您不能这样做,因为您foundParser可以是任何后代,而不是该给定ItemParser实例的一个真正的预期类型。它T应该猜哪个?!这不可以。
因此,您必须围绕基类而不是后代设计API。您使编译器无法知道将传递给该parse()方法的内容。您可以知道的唯一一件事是它是一个BaseItem实例。
只有您知道使用映射进行操作的技巧,可以确保您使用正确的类型调用正确的实例。编译器不知道使您保证的逻辑。
我建议您更改您的API,以添加一个internalParse您要强制执行其工作的方法,并由一个经过仔细parse检查和执行恶意强制转换的通用函数来包装。
abstract class BaseItem
class AmericanItem : BaseItem()
class EuropeanItem : BaseItem()
interface ItemParser<T: BaseItem> {
@Suppress("UNCHECKED_CAST")
fun parse(item: BaseItem) {
val tempItem = item as? T
?: throw IllegalArgumentException("Invalid type ${item.javaClass.name} passed to this parser")
internalParse(tempItem)
}
fun internalParse(item: T)
}
class AmericanItemParser : ItemParser<AmericanItem> {
override fun internalParse(item: AmericanItem) {
println("AmericanItemParser")
}
}
class EuropeanItemParser : ItemParser<EuropeanItem> {
override fun internalParse(item: EuropeanItem) {
println("parsing EuropeanItem")
}
}
fun main(args: Array<String>) {
val hashMap = HashMap<Class<out BaseItem>, ItemParser<*>>()
hashMap.put(AmericanItem::class.java, EuropeanItemParser())
hashMap.put(EuropeanItem::class.java, AmericanItemParser())
val inputItem = EuropeanItem()
val foundParser = hashMap[inputItem.javaClass]
foundParser?.parse(inputItem)
}
Run Code Online (Sandbox Code Playgroud)
请注意,您也可以使用Kotlin类而不是类型为Java的Java类KClass<out T>。
| 归档时间: |
|
| 查看次数: |
1150 次 |
| 最近记录: |