以一个具体的方法为例,
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)
^
现在我所有的技巧都用尽了。
我该怎么做?
关于你的第一个定义:
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中并非如此。但是我们有下一个最好的东西:类型类(有关一些信息,请参阅此问题:Scala 中的类型类有什么用?(。类型类在 Scala 中使用隐式实现。
适合您的解决方案是:
def df[T](f: T => T, dt: T)(implicit num: Numeric[T]) = (t: T) => num.minus(f(num.plus(t, dt)), f(t))
该方法是泛型的,但它也需要存在一个对象num
该对象知道如何对类型T
的对象执行诸如plus
、minus
等操作,并且是隐式传递的。幸运的是,Scala 库为所有基元数字类型 Int、Double 等提供了 Numeric
实例,因此您不必这样做。
后期编辑:
正如Jesper Nordenberg和Régis Jean-Gilles指出的那样,你实际上可以使用import来获取初始表达式:
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
不过你应该小心。如果您正在进行繁重的数学计算,则此解决方案可能会出现性能问题,主要是因为装箱。
希望对您有所帮助!
对任意类型T
执行t + dt
,因为不能保证+
对于T
存在——事实上,大多数类型都没有定义+
。
它也不适用于T <: Double
,因为Double
子类上+
的方法返回一个Double
,并且f
要求将T
传递给它。
现在,您可能正在寻找一种进行通用数学的方法 - 也就是说,忽略传递给您的确切数字类型。这在 Scala 中并不容易做到,特别是如果你也想要性能的话。你可以访问我的这个老问题,尽管现在有更有效的方法。如果你想要效率,看看Spire。