【发布时间】:2016-04-17 11:59:30
【问题描述】:
我遇到了一个有趣的情况。我想实现如下所示的东西。
object Test {
abstract class Key[A]
class Constraint[-A] {
def doSomething(a: A): String = ""
}
object DesiredKeyConstraints {
case class KeyConstraint[A](val key: Key[A], constraint: Constraint[A])
val data: Map[Key[_], KeyConstraint[_]] = Map()
}
def useTheKeyConstraints[A](key: Key[A], value: A): String = {
DesiredKeyConstraints.data.get(key).fold[String]("") {
case DesiredKeyConstraints.KeyConstraint(_, constraint) => constraint.doSomething(value)
}
}
def main(args: Array[String]) {
println("hi")
}
}
不幸的是,当我从地图中拉出 KeyConstraint 时,我不再知道它的类型。所以,当我尝试拨打doSomething 时,类型不会签出。这一切似乎都按预期进行。有趣的是,在代码库的其他地方,我们有如下内容:(将 DesiredKeyConstraints 替换为 WorkingKeyConstraints)
object Test {
abstract class Key[A]
class Constraint[-A] {
def doSomething(a: A): String = ""
}
object WorkingKeyConstraints {
sealed trait SuperTrait[A, B] {
val key: Key[A]
}
case class KeyConstraint[A](val key: Key[A], constraint: Constraint[A]) extends SuperTrait[A, Unit]
val data: Map[Key[_], SuperTrait[_, _]] = Map()
}
def useTheKeyConstraints[A](key: Key[A], value: A): String = {
WorkingKeyConstraints.data.get(key).fold[String]("") {
case WorkingKeyConstraints.KeyConstraint(_, constraint) => constraint.doSomething(value)
}
}
def main(args: Array[String]) {
println("hi")
}
}
这个编译和运行得很好。出于某种原因,拥有超类型意味着当我们从 Map 中提取 KeyConstraint 时,它会将其视为 KeyConstraint[Any] 而不是 KeyConstraint[_]。因为Constraint 是逆变的,所以我们可以将Constraint[Any] 视为Constraint[A],因此代码可以编译。这里的关键问题/问题是,为什么拥有超类型会导致类型检查器将其视为KeyConstraint[Any]?
另外,作为进一步的信息,我对此进行了更多尝试,它是特定于具有两个泛型类型参数的超类型的东西。如果我用两个泛型类型来做子类,或者用一个泛型类型来做父类,它仍然会失败。在下面查看我的其他失败尝试:
object AnotherCaseThatDoesntWorkKeyConstraints {
case class KeyConstraint[A, B](val key: Key[A], constraint: Constraint[A])
val data: Map[Key[_], KeyConstraint[_, _]] = Map()
}
object AThirdCaseThatDoesntWorkKeyConstraints {
sealed trait SuperTrait[A] {
val key: Key[A]
}
case class KeyConstraint[A](val key: Key[A], constraint: Constraint[A]) extends SuperTrait[A]
val data: Map[Key[_], SuperTrait[_]] = Map()
}
我认为这是 Scala 类型检查器中的某种错误,但也许我遗漏了一些东西。
【问题讨论】:
-
它是如何失败的?哪条线和什么错误?目前,你所有的例子都为我编译。
-
@AlvaroCarrasco,不是第一个,对吧?
标签: scala generics subclass contravariance