它不会编译,因为一旦您编写Board[_]
,编译器就不会推断出关于匿名类型参数的任何有用信息_
。
有几种解决方法(与您已经提出的不同):
- 利用
Board[X] forSome { type X <: Board[X] }
- 使用模式匹配来推断有关类型的更多信息
使用forSome
存在量化
这可以通过forSome
-existential 量化轻松解决:
import scala.language.existentials
object BoardOps_forSome {
def updated(board: Board[X] forSome { type X <: Board[X] }) = {
board.updated.updated.updated
}
}
这使您可以updated
无限次调用。
使用模式匹配
您实际上可以在不更改签名的情况下使用模式匹配来解决它。例如,这种不敬虔的构造允许您应用该方法updated
三次(工作次数不受限制):
object BoardOps_patternMatch {
def updated(board: Board[_]) = {
board match {
case b: Board[x] => b.updated match {
case c: Board[y] => c.updated match {
case d: Board[z] => d.updated
}
}
}
}
}
这是因为一旦将未知类型绑定到类型变量x
, y
, z
,编译器就会被迫做一些额外的推理工作,并推断它实际上必须是x <: Board[_$?]
等等。不幸的是,它一次只进行一个步骤,因为如果它试图计算最精确的类型,类型计算就会发散。
上限和全称不一样
请注意,您的第一个解决方法仅适用于两次:
object BoardOps_upperBound_once {
def updated(board: Board[_<:Board[_]]) = {
board.updated.updated // third .updated would not work
}
}
因此,它不等同于您的第二个解决方法,它也可以无限次工作,这里以三个调用为例updated
:
object BoardOps_genericT {
def updated[T <: Board[T]](board: T) : T = {
board.updated.updated.updated
}
}