我有以下代码段:
class Statistics[T, U <: NumberLike[T]] {
def mean(xs: Vector[U]): U =
xs.reduce(_ + _) / xs.size
}
trait NumberLike[T] {
def + (that: NumberLike[T]): NumberLike[T]
def / (that: Int): NumberLike[T]
}
它编译错误:
error: type mismatch;
found : NumberLike[T]
required: U
xs.reduce(_ + _) / xs.size
^
one error found
我不明白为什么编译器不接受这个;我已经定义U
应该是NumberLike[T]
的子类。
答案 0 :(得分:2)
错误消息确切地说明出了什么问题:您的mean
方法承诺返回U
,而是返回NumberLike[T]
。
你可以通过F-bounded多态来解决它:
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
带有+
和/
的精确返回类型。它现在可以保证返回NumberLike
。
Res
由于您似乎无法在任何地方使用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-bounded多态,并且可以为相同的功能提供不同的语法样式。与具有F-有界多态性的复杂类层次结构相比,类型类更倾向于组合。
答案 1 :(得分:1)
错误有点误导,但如果仔细观察,^
位于+
上,则意味着该操作的返回类型错误。
问题在于+
和/
是返回NumberLike[T]
的操作,但您需要U
作为{{1}的返回类型}。
由于函数在返回类型中是协变的,因此无法返回mean
预期NumberLike
的位置。
考虑到这一点,您可以通过确保U
操作返回更精确的类型来解决此问题:
NumberLike
现在你的trait NumberLike[T] {
def +[A <: NumberLike[T]](that: A): A
def /[A <: NumberLike[T]](that: Int): A
}
定义应该编译。
答案 2 :(得分:0)
在reduce
中,预计二元运算符具有统一签名,在本例中为(U, U) => U
,但在您的情况下为(U, NumberLike[T]) => NumberLike[T]
。
由于mean
,+
,/
中的预期结果类型,即使您修复了特征,这也无法发挥作用。您告诉U
mean
+
,而/
中的NumberLike
,NumberLike[T]
方法返回[root@server ~]# php -v
PHP Warning: Module 'ionCube Loader' already loaded in Unknown on line 0
The ionCube PHP Loader is disabled because of startup problems.
PHP 5.3.3 (cli) (built: Mar 22 2017 12:27:09)
值,而不是[root@server ~]# php -v
Failed loading /usr/lib64/php/modules/ioncube_loader_lin_5.3.so: /usr/lib64/php/modules/ioncube_loader_lin_5.3.so: cannot open shared object file: No such file or directory
Failed loading /usr/lib64/php/modules/ioncube_loader_lin_5.3.so: /usr/lib64/php/modules/ioncube_loader_lin_5.3.so: cannot open shared object file: No such file or directory
的子类型。 (Scala不支持MyTypes,但this question可能对您有用。)