您正在调用+
on 方法A
,但不能保证A
有这样的方法。有两种方法可以解决这个问题:继承或类型类。
使用继承,找到所有所需类的共同祖先(包括您想要的方法)将是一件简单的事情,然后您将编写[A <: CommonAncestor]
. 不幸的是,由于努力使 Scala 与 Java 和一般 JVM 限制互操作,数字原语没有这样的祖先。
那么,我们就剩下类型类了。“类型类”这个表述来自 Haskell,其思想是可以将不同的类型分组到一个类中,这些类具有一些共同的属性。它与继承之间的主要区别在于类型类对扩展是开放的:您可以轻松地将任何类型添加到这样的类中。
Scala 没有直接类型类支持。相反,我们使用“类型类模式”来模拟它。基本上,我们创建了一个类——类型类——它包含我们想要的方法。接下来,我们为我们希望支持的每种类型创建该类的实例。最后,我们隐式传递这些实例,这使得编译器的工作是找到所需的实例。
在您的示例中,我们可以这样做:
// Our type class
class Addable[T] {
def plus(a: T, b: T): T
}
// Or Int instance
object AddableInt {
class AddableInt extends Addable[Int] {
def plus(a: Int, b: Int): Int = a + b
}
implicit val addableInt = new AddableInt
}
// Make the implicit available
import AddableInt._
// Make recFunc use it
def recFunc[A](xs: List[A], base : () => A)(implicit addable: Addable[A]): A =
if (xs.isEmpty) base() else addable.plus(xs.head, recFunc(xs.tail, base))
// call recFunc
recFunc(List(1, 2, 3), () => 0)
有很多方法可以改善这一点,例如使用隐式类和上下文边界。请参阅 Stack Overflow 上的Scala wiki,了解有关隐式和上下文边界的更多信息(分别为第 23 和第 19 节)。
现在,Scala 已经有了基本算术的上下文边界,甚至还有一些使用视图边界的额外技巧来使其无缝使用。以下是如何使其仅与标准库一起使用:
import scala.math.Numeric.Implicits._
def recFunc[A : Numeric](xs: List[A], base : ()=>A) : A =
if (xs.isEmpty) base() else xs.head + recFunc(xs.tail, base)
另请参阅Numeric scaladoc,尽管它的示例非常少。