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

jim*_*myb 29 polymorphism scala

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

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

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

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

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

我需要为此实现一个特征吗?

Dan*_*ral 32

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

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

为了说得更清楚,Java和,因此,斯卡拉,不看之间的任何共同点Double+和一个Int+.

Scala最终解决这个限制的方式是使用Numeric及其子类,Fractional以及Integral所谓的类型模式.基本上,你这样使用它:

def square[T](x: T)(implicit num: Numeric[T]): T = {
    import num._
    x * x
}
Run Code Online (Sandbox Code Playgroud)

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

def numberAndSquare[T : Numeric](x: T) = x -> square(x)
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅我自己的问题中的答案.


Aar*_*rup 10

您可以定义square为:

def square[T: Numeric](x: T): T = implicitly[Numeric[T]].times(x,x)
Run Code Online (Sandbox Code Playgroud)

这种方法的优点是它适用于任何具有隐式转换为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(_)
}
Run Code Online (Sandbox Code Playgroud)

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

或者,可以调用List(1,2,3).map(square(_)),正如Derek Williams在scala-user邮件列表中指出的那样.