如何在kotlin中将通用映射指定为超类

时间:2018-01-18 18:46:17

标签: generics kotlin

我想知道在这种特殊情况下如何正确使用输入/输出方差修饰符。

我有一个具有特定实现类型的通用Map,我想将它分配给更通用类型的变量:

var generalMap: Map<SimpleExpression<Any>, Any> = emptyMap()
var specificMap: Map<StringExpression, String?> = makeSomeMap()

generalMap = specificMap // this assignment won't compile :(

此外,StringExpression扩展了SimpleExpression<String>。我尝试使用out方差修饰符在generalMap定义上以几种不同的方式进行修改:

var generalMap: Map<out SimpleExpression<Any>, out Any?> = emptyMap()

...但遗憾的是遇到了相同的编译错误。

2 个答案:

答案 0 :(得分:2)

Map不是密钥类型的变体,因为它位于in位置.get()out位置.keys()。将其视为out并不安全,因为

var specificMap: Map<StringExpression, String?> = makeSomeMap()
var generalMap: Map<SimpleExpression<Any>, Any> = specificMap
generalMap[intExpression]  // specificMap.get(not a StringExpression)

话虽如此,如果您认为这不会导致Map返回的特定makeSomeMap()实现出现任何实际问题,则无法阻止您进行未经检查的演员。

答案 1 :(得分:2)

只有在SimpleExpression<T> 仅生成 T值时才可以进行此类分配。如果是这样,请按以下方式进行界面或类声明:

interface SimpleExpression<out T> 

接下来你必须改变它是generalMap的声明。将out方差添加到SimpleExpression<..>并使Any可以为空:

var generalMap: Map<out SimpleExpression<Any>, Any?> = emptyMap()

之后,编译器允许您安全地将specificMap分配给generalMap

如果生成并使用了T中的SimpleExpression(包含fun consume(t: T)fun produce(): T等方法),那么您应该声明generalMap像这样:

var generalMap: Map<out SimpleExpression<*>, Any?> = emptyMap()