0

现在我有一个RealVector班级和ComplexVector班级。它们的逻辑几乎相同,所以我想将它们组合成一个Vector类。RealVector需要一个List[Double]ComplexVector需要一个List[ComplexNumber]whereComplexNumber是我创建的一个案例类。

我如何使它case class Vector接受这两种List类型中的任何一种?请注意,虽然大多数方法的代码是相同的,但其中一些可能会返回 aDoubleComplexNumber取决于List类型。在这种情况下使用案例类是否正确,或者我应该使用普通类?

编辑:我当前的代码

trait VectorElement[A]
implicit object RealVectorElement extends VectorElement[Double]
implicit object ComplexVectorElement extends VectorElement[ComplexNumber]

case class MyVector[A: VectorElement](components: List[A]) {
    def +(that:MyVector[A]):MyVector[A] = {
        if (this.dimension != that.dimension) throw new Exception("Cannot add MyVectors of different dimensions.");
        new MyVector((this.components zip that.components).map(c => c._1 + c._2));
    }

    def -(that:MyVector[A]):MyVector[A] = {
        if (this.dimension != that.dimension) throw new Exception("Cannot subtract MyVectors of different dimensions.");
        new MyVector((this.components zip that.components).map(c => c._1 - c._2)); // ERROR HERE: error: value - is not a member of type parameter A
    }
    ...
}
4

2 回答 2

2

最熟悉的方法是创建两个 Vector 类的通用超类型

abstract class Vector[A](elements: List[A]){
  //common code
}
case class RealVector(elements: List[Double]) extends Vector[Double](elements)
case class ComplexVector(elements: List[ComplexNumber]) extends Vector[ComplexNumber](elements)

如果您只想要一种类型,可以将泛型与案例类一起使用case class Vector[A](values: List[A])

现在这将允许任何类型的列表,所以让我们缩小范围。如果我们正在处理自定义类型,我们可以使用来自 trait 的公共超类型,但Double它是内置的,我们无法修改它。

我们可以做的是使用类型类,这是 scala 中可能的一种灵活的多态形式。我们可以用 trait 定义我们的类型类。

trait VectorElement[A]

如果我们只是想用它来标记我们想要完成的类型,但我们也可以在这里放入我们需要的常用功能。

如果我们将案例类定义修改为

case class Vector[A: VectorElement](values: List[A])

我们将泛型类型限制为仅具有可用 VectorElement 实例的那些类型。上面的代码是语法糖case class Vector[A](values: List[A])(implicit ev: VectorElement[A])

我们现在可以为我们需要的类型创建实例

implicit object RealVectorElement extends VectorElement[Double]
implicit object ComplexVectorElement extends VectorElement[ComplexNumber]

现在只要这两个隐式对象在范围内,我们就可以在我们的Vector类中使用这些类型,但不能在其他类中使用。


一些不相​​关的建议:

Vector已经是标准库中的一个总是自动导入的类,这有可能导致问题

List可能不是最好的集合类型,因为它需要遍历集合才能访问它的元素。您可能想要选择更通用的东西,并且您可能想要良好的索引访问。如果您使用IndexedSeq而不是List作为集合类型,则可以确保您使用的集合具有良好的基于​​索引的随机访问,例如Arrayor Vector(来自标准库的那个)。

于 2017-08-24T18:38:08.130 回答
1

您可以尝试使用一些更高级的 Scala 类型系统功能:

object Types {
  trait inv[-A] {}
  type Or[A, B] = {
    type check[X] = (inv[A] with inv[B]) <:< inv[X]
  }
}

case class Vector[U : (Double Or Int)#check](list: List[U]) {
  def first(): U = list.head
}

我用过Doubleand Inthere 但可以使用任何类型。用法很简单:

println(Vector(List(1.0, 2.0, 3.0)).first()) // prints a Double
println(Vector(List(1, 2, 3)).first()) // prints an Int
//Vector(List("String")).first() // won't compile
于 2017-08-24T18:26:25.957 回答