【问题标题】:type parameterization of ScalaScala 的类型参数化
【发布时间】:2013-02-22 14:42:45
【问题描述】:

以具体方法为例,

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)
                                                             ^

现在我所有的把戏都用完了。

我该怎么做?

【问题讨论】:

    标签: scala types parameterization


    【解决方案1】:

    关于你的第一个定义:

    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 中使用隐式实现。

    您的解决方案是:

    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 类型的对象执行plusminus 等操作,并且该对象是隐式传递的。幸运的是,Scala 库为所有基本数字类型 Int、Double 等提供了 Numeric 实例,因此您不必这样做。

    稍后编辑:

    正如 Jesper Nordenberg 和 Régis Jean-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

    不过你应该小心。如果您进行繁重的数学计算(主要是因为装箱),此解决方案可能会出现性能问题。

    希望对你有帮助!

    【讨论】:

    • 你也可以使用import num._ 让操作符在类型T上工作。
    • @JesperNordenberg 我最初尝试过,我用+- 编写了问题中的函数,但添加dt 时出现错误 - 找到T,预期字符串.由于某种原因,隐式转换未被拾取。
    • @JesperNordenberg 另外,你的意思是import Numeric._ 吗? import num._ 不起作用
    • 为我工作,def df[T](f: T =&gt; T, dt: T)(implicit num: Numeric[T]) = (t: T) =&gt; {import num._; f(t + dt) - f(t)}。你使用的是哪个 Scala 版本?
    • 好吧,我没想到你指的是变量num 。我认为这是一个命名空间。我更新了我的答案,谢谢!
    【解决方案2】:

    您不能对任意类型 T 执行 t + dt,因为不能保证 + 存在于 T —— 事实上,大多数类型都没有定义 +

    它也不适用于T &lt;: Double,因为Double 子类上的方法+ 返回Double,而f 要求将T 传递给它。

    现在,您可能正在寻找一种进行通用数学运算的方法——也就是说,忽略传递给您的确切数字类型。这在 Scala 中并不容易做到,尤其是如果您还想要性能的话。您可以访问this old question of mine,尽管现在有更有效的方法。如果你想要效率,请查看Spire

    【讨论】:

    • 这对我帮助很大。谢谢!
    猜你喜欢
    • 2011-02-19
    • 1970-01-01
    • 2018-09-24
    • 1970-01-01
    • 2021-04-20
    • 2011-10-05
    • 2012-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多