为什么不编译?
给出的错误是class SomeElement needs to be abstract, since method eval in trait Element of type [T <: Typed]=> scala.util.Try[T] is not defined
我无法理解为什么SomeElement上定义的方法eval
不满足类型约束。
据我了解,eval
应该返回包含在Try
子类Typed
中的内容。
Try在其类型参数中是协变的。 eval
中SomeElement
的实施将返回NumberLike
和NumberLike
子类Typed
。出了什么问题?
import scala.util.Try
trait Element {
def eval[T <: Typed]: Try[T]
}
trait Typed
case class NumberLike(n: Long) extends Typed
case class SomeElement(n: Long) extends Element {
def eval = Try {
NumberLike(n)
}
}
object app extends Application {
println (SomeElement(5).eval)
}
尝试在SomeElement
中向eval添加显式类型参数也无济于事:
case class SomeElement(n: Long) extends Element {
def eval[NumberLike] = Try {
NumberLike(n)
}
}
将SomeElement的定义更改为上面给出:
found : <empty>.NumberLike
required: NumberLike(in method eval)
NumberLike(n)
编辑我真的想知道为什么这不能编译。问题的解决方法很有帮助,但我真的想知道这里发生了什么。
答案 0 :(得分:2)
类型参数T
是在函数上定义的,而不是在封闭类型Element
上定义的,它不能通过继承来“擦除”,并且必须保留在重写函数上({{3 }})。
将type参数移动到Element
定义使其工作如下。
trait Element[T <: Typed] {
def eval: Try[T]
}
trait Typed
case class NumberLike(n: Long) extends Typed
case class SomeElement(n: Long) extends Element[NumberLike] {
def eval = Try {
NumberLike(n)
}
}
或使用类型成员:
trait Element {
type T <: Typed
def eval: Try[T]
}
trait Typed
case class SomeElement(n: Long) extends Element {
type T = NumberLike
def eval = Try {
NumberLike(n)
}
}
答案 1 :(得分:0)
既然有人给出了解决方案,我就试图解释原因。
在java中,这样的东西是非法的:
class A {
<T> T f() {return null;}
Object f() {return null;}
}
但是在scala中,这是合法的:
class A {
def f[T](): T = ???
def f(): Any = ???
}
主要区别在于:scala处理2个具有相同名称和参数的方法列表不同,如果其中一个具有类型参数而另一个没有。(我认为scala方法的签名包括类型参数,如果我是正确的我错:))
因此,在您的情况下,您不能通过普通方法覆盖带有类型参数的方法。(它们具有不同的签名)
我不确定哪一个更好,我个人更喜欢scala规则:)