Scala: 泛型类类型的约束

7

我对Scala非常陌生。

我想实现一个通用的矩阵类"class Matrix[T]"。对T唯一的限制是T必须实现"+"和"*"方法/函数。我该如何去做呢?

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

我考虑了以下思路:

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 
}

一切类型检查都没问题,但我仍然无法实例化一个矩阵。我是否缺少隐式构造函数?我该如何做才能实现它?或者我的方法完全错误?

提前感谢 Troels

3个回答

4

终于找到答案了 :-) 我想我的第一次尝试并不那么遥远。以下是答案:(适用于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) 

4
你可以使用Scala 2.8的Numeric来实现。这里有一个描述:here。它将替换MatrixElement及其实现:
class Matrix[T : Numeric](data: Array[Array[T]]) {
   def *(that: Matrix[T]) = //
}

我考虑过Numeric。但我真的不知道如何让它适用于我的类型,例如Complex。 我认为Complex需要扩展Numeric。首先,这将要求我实现比+和更多的方法。其中包括排序-据我所知,复数没有严格的排序。 关键是我需要Matrix能够在任何实现了+和方法的类型上工作。 - Troels Blum
有很多方法可以实现,如果你只需要+和*。但是你仍然可以使用这两种方法创建类似Numeric的东西。这应该不需要太多工作。(如果值得的话,稍后可以回来并用Numeric替换它。) - Thomas Jung
1
@troels 你可以根据实部进行排序,或者对所有比较返回“0”。你也可以使用 error("Undefined method") 来“实现”方法。请注意,Complex 不会 扩展 Numeric。相反,将存在一个 Numeric[Complex] 的实例。 - Daniel C. Sobral
如何实现Numeric[T]的子类型? 我一直在寻找相关指南,但没有找到。 同时也发布了一个单独的问题:https://dev59.com/nUzSa4cB1Zd3GeqPiwOw - Troels Blum

2
这是使用 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 中编写这个吗? :-) - Thomas Jung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接