Scala的类型参数化

时间:2013-02-22 14:42:46

标签: scala types parameterization

举一个具体的方法,例如,

def df(f: Float => Float, dt: Float) = (t: Float) => f(t + dt) - f(t)

它可以编译和工作。但是,当我尝试以通用方式定义它时,

def df[T](f: T => T, dt: T) = (t: T) => f(t + dt) - f(t)

编译说,

  

“错误:类型不匹配;找到:T;必需:字符串def df [T](f:T =>   T,dt:T)=(t:T)=> f(t + dt) - f(t)“。

似乎无法添加T类型。然后我尝试了另一种方式,

def df[T <: Double](f: T => T, dt: T) = (t: T) => f(t + dt) - f(t)

再次失败,

scala> def df[T <: Double](f: T => T, dt: T) = (t: T) => f(t + dt) - f(t)
<console>:7: error: type mismatch;
 found   : Double
 required: T
       def df[T <: Double](f: T => T, dt: T) = (t: T) => f(t + dt) - f(t)
                                                             ^

现在我的所有技巧都已经筋疲力尽了。

我该怎么做?

2 个答案:

答案 0 :(得分:2)

关于你的第一个定义:

def df[T](f: T => T, dt: T) = (t: T) => f(t + dt) - f(t)

这不可能是因为我们无法知道T类型是否有“+”或“ - ”方法。

您的第一个定义,

def df[T <: Double](f: T => T, dt: T) = (t: T) => f(t + dt) - f(t)

短篇小说 - 不能从Double延伸,即使+方法可能需要另一个双倍而不是T

为了做到这一点,我们需要一个适用于所有数字类型并声明所有数字运算符的统一特征。不幸的是,Scala不是这种情况。但我们有下一个最好的东西:输入类(请参阅此问题以获取一些信息:What are type classes in Scala useful for?)。类型类在Scala中使用implicits实现。

您的解决方案是:

def df[T](f: T => T, dt: T)(implicit num: Numeric[T]) = (t: T) => num.minus(f(num.plus(t, dt)), f(t))

该方法是通用的,但它还需要存在一个对象num,它知道如何对plusminus等类型的对象执行操作T并且它是隐式传递的。幸运的是,Scala库为所有原始数字类型Int,Double等提供了Numeric的实例,因此您不必这样做。

LATER EDIT:

正如Jesper Nordenberg和RégisJean-Gilles所指出的那样,您实际上可以使用导入来获得初始表达式:

def df[T](f: T => T, dt: T)(implicit num: Numeric[T]): (T => T) = {
  import num._
  (t: T) => f(t + dt) - f(t)
}

这也是使用隐式转换实现的。 您可以查看Numeric的源文件,了解有关正在进行的操作的更多信息:Numeric.scala

你应该小心。如果你正在进行繁重的数学计算,这个解决方案可能会出现性能问题,主要是因为拳击。

希望它有所帮助!

答案 1 :(得分:1)

对于任意类型t + dt,您无法T,因为无法保证+存在T - 事实上,大多数类型都没有定义{ {1}}。

它对+也不起作用,因为T <: Double子类上的方法+返回DoubleDouble要求f传递给它。

现在,你可能正在寻找一种做泛型数学的方法 - 也就是说,忽略传递给你的确切数字类型。在Scala中这并不容易,特别是如果你想要性能的话。您可以访问this old question of mine,但现在有更有效的方法。如果你想要效率,请看Spire