【问题标题】:Scala: Constraint on generic class typeScala:对泛型类类型的约束
【发布时间】:2011-01-17 10:04:01
【问题描述】:

我对 Scala 很陌生。

我想实现一个通用矩阵类“class Matrix[T]”。对 T 的唯一约束应该是 T 应该实现一个“+”和一个“*”方法/函数。我该怎么做?

例如,我希望能够同时使用 Int、Double 和我自己定义的类型,例如复杂

我在想一些事情:

class Matrix[T <: MatrixElement[T]](data: Array[Array[T]]) {
   def *(that: Matrix) = ..// code that uses "+" and "*" on the elements
}
abstract class MatrixElement[T] {
    def +(that: T): T
    def *(that: T): T 
}
implicit object DoubleMatrixElement extends MatrixElement[Double]{
    def +(that: Double): Double = this + that
    def *(that: Double): Double = this * that 
}
implicit object ComplexMatrixElement extends MatrixElement[Complex]{
    def +(that: Complex): Complex = this + that
    def *(that: Complex): Complex = this * that 
}

所有类型都会检查,但我仍然无法实例化矩阵。我是否缺少隐式构造函数?我该怎么做呢?还是我的方法完全错了?

提前致谢 巨魔

【问题讨论】:

    标签: generics scala scala-2.8


    【解决方案1】:

    为此,您可以将Numeric 用于 Scala 2.8。它是描述here。它将取代 MatrixElement 及其实现:

    class Matrix[T : Numeric](data: Array[Array[T]]) {
       def *(that: Matrix[T]) = //
    }
    

    【讨论】:

    • 我考虑过数字。但我真的不明白这对我自己的类型如何起作用,例如复杂的。我认为 Complex 需要扩展 Numeric。这首先需要我实现比 + 和 * 更多的方法。在这些排序中 - 据我所知,复数没有严格的排序。关键是我需要 Matrix 来处理任何类型,这些类型只是完全填充了方法 + 和 * 的实现。
    • 如果只需要+和*的话,有很多方法可以实现。但是您仍然可以仅使用这两种方法创建类似于 Numeric 的内容。这应该是两个很大的工作。 (如果值得的话,也许稍后再回来并用数字替换它。)
    • @troels 您始终可以按实部排序,或者只是简单地返回“0”进行所有比较。而且你总是可以用error("Undefined method")“实现”这些方法。但请注意,Complex 不会扩展 Numeric。相反,会有一个Numeric[Complex] 的实例。
    • 如何实现 Numeric[T] 的子类型?我一直在寻找这方面的指南,但没有找到。也将其作为一个单独的问题发布:stackoverflow.com/questions/2274718/…
    【解决方案2】:

    终于找到了答案 :-) 我想我在第一次尝试时并没有那么遥远。 在这里:(为 scala 2.8 编写)

    trait MatrixElement[T] {
        def +(that: T): T
        def *(that: T): T 
    }
    
    object MatrixElement {
        implicit def intToMatrixElement(x : Int) = new MatrixElement[Int] {
            def +(y : Int) = x + y
            def *(y : Int) = x * y
        }
        implicit def doubleToMatrixElement(x : Double) = new MatrixElement[Double] {
            def +(y : Double) = x + y
            def *(y : Double) = x * y
        }
        implicit def complexToMatrixElement(x : Complex) = new MatrixElement[Complex] {
            def +(y : Complex) = x + y
            def *(y : Complex) = x * y
        }
    }
    
    class Matrix[T  <% MatrixElement[T] : ClassManifest ](d: Array[Array[T]]) {
        def *(that: Matrix) = ..// code that uses "+" and "*" on the elements
    }
    

    现在我可以执行以下操作:

    scala> new Matrix(Array(Array(1,0),Array(0,1)))
    res0: Matrix[Int] = 
    1 0 
    0 1 
    
    scala> new Matrix(Array(Array(new Complex(0),new Complex(1)),Array(new Complex(1),new Complex(0))))
    res9: Matrix[Complex] = 
    (0.0,0.0i) (1.0,0.0i) 
    (1.0,0.0i) (0.0,0.0i) 
    

    【讨论】:

      【解决方案3】:

      Numeric 解决方案的外观如下:

      // ': Numeric[T]' adds an implicit parameter to the constructor,
      // which allows T to be used in arithmetic expressions.
      class Matrix[T: Numeric](val data: Array[Array[T]]) {
         def *(that: Matrix[T]) = {
             val nt = implicitly[Numeric[T]]
             import nt._  // This imports an Implicit View to allow operator syntax
      
             this.data(0)(0) * that.data(0)(0)
             // etc
         }
      }
      

      【讨论】:

      • T: Numeric[T] 应该是 T: Numeric。你在没有 REPL 的情况下写这个吗? :-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-21
      • 1970-01-01
      • 1970-01-01
      • 2022-10-06
      • 1970-01-01
      相关资源
      最近更新 更多