Scala:为什么下面会出现类型不匹配错误?

时间:2018-03-31 08:12:04

标签: scala types

我有以下代码段:

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]的子类。

3 个答案:

答案 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 +,而/中的NumberLikeNumberLike[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可能对您有用。)

相关问题