错误消息准确地说明了问题所在:您的 mean 方法承诺返回 U,但它却返回了 NumberLike[T]。
你可以通过 F-bounded polymorphism 来解决它:
class Statistics[T, U <: NumberLike[T, U]] {
def mean(xs: Vector[U]): U =
xs.reduce(_ + _) / xs.size
}
trait NumberLike[T, Res <: NumberLike[T, Res]] {
def + (that: NumberLike[T, Res]): Res
def / (that: Int): Res
}
这行得通,因为现在NumberLike 带有+ 和/ 的精确返回类型。它现在保证返回一个Res,而不是返回一些未指定的NumberLike。
由于您似乎没有在任何地方使用T 类型,因此如果您完全省略T,实际上会更清楚:
class Statistics[U <: NumberLike[U]] {
def mean(xs: Vector[U]): U =
xs.reduce(_ + _) / xs.size
}
trait NumberLike[U <: NumberLike[U]] {
def + (that: NumberLike[U]): U
def / (that: Int): U
}
请注意,现在+ 返回一个U,而不仅仅是一些不相关的NumberLike[T]。
实际上,您应该考虑将功能(加法、除法)与运算符的语法糖分开。您可以将实际计算移到单独的类型类中,并通过隐式类提供+、/ 方法:
/* The operations */
trait NumberTypeclass[U] {
def add(a: U, b: U): U
def divideByInt(a: U, i: Int): U
}
/* The syntactic sugar */
implicit class NumberOps[U: NumberTypeclass](u: U) {
def +(other: U): U = implicitly[NumberTypeclass[U]].add(u, other)
def /(i: Int): U = implicitly[NumberTypeclass[U]].divideByInt(u, i)
}
/* Usage example */
class Statistics[U: NumberTypeclass] {
def mean(xs: Vector[U]): U = {
xs.reduce(_ + _) / xs.size
}
}
乍一看,它有点冗长,但它的优点是可以省略复杂的 F 有界多态,并且可以为相同的功能提供不同的语法样式。类型类也往往比具有 F 有界多态性的复杂类层次结构更好。