如何在Scala中实现通用数学函数

时间:2010-10-29 22:47:45

标签: scala polymorphism

我刚刚开始使用Scala,我认为应该很容易理解这一点。我正在尝试实现以下功能:

def square(x:Int):Int = { x * x }

这很好用,但是如果我想尝试让这个功能适用于任何类型的数字,我希望能够做到以下几点:

def square[T <: Number](x : T):T = { x * x }

这抱怨并说:error:value *不是类型参数T的成员

我是否需要为此实现特征?

2 个答案:

答案 0 :(得分:32)

这是我在Stack Overflow中的first questions之一或关于Scala的。问题是Scala保持与Java的兼容性,这意味着它的基本数字类型等同于Java的原语。

问题出现在Java原语不是类,因此,没有允许“数字”超类型的类层次结构。

更明确地说,Java,以及Scala,在Double +Int {{1}之间没有看到任何共同点。 }}

Scala最终解决此限制的方式是使用+及其子类NumericFractional,即所谓的类型类型。基本上,你这样使用它:

Integral

或者,如果您不需要任何数字操作,但需要调用的方法,则可以使用上下文绑定语法进行类型声明:

def square[T](x: T)(implicit num: Numeric[T]): T = {
    import num._
    x * x
}

有关详细信息,请参阅我自己的问题中的答案。

答案 1 :(得分:10)

您可以将square定义为:

def square[T: Numeric](x: T): T = implicitly[Numeric[T]].times(x,x)

这种方法的优点是它适用于任何具有隐式转换为Numeric [T]的类型T(即Int,Float,Double,Char,BigInt,...或您提供的任何类型)隐式转换)。

修改 不幸的是,如果你尝试List(1,2,3).map(square)之类的东西,你会遇到麻烦(具体来说,你会得到一个编译错误,比如“无法找到Numeric [T]类型的证据参数的隐含值”。为了避免这个问题,你可以重载square来返回一个函数:

object MyMath {
   def square[T: Numeric](x: T) = implicitly[Numeric[T]].times(x,x)
   def square[T: Numeric]: T => T = square(_)
}

希望对类型推断器有更好理解的人会解释为什么会这样。

或者,正如Derek Williams在scala-user mailing list thread中指出的那样,可以致电List(1,2,3).map(square(_))