只实现一次抽象行为...将特征作为契约,抽象 class 作为具体助手

Implement abstract behaviour just once... trait as contract, abstract class as concrete-helper

我目前正在考虑重构我的个人线性代数包。 真正困扰我的一件事是:

目前我只支持由 float 组成的向量和矩阵。现在我想添加对 ints、doubles 甚至 booleans 的支持,但我必须考虑一下。

有一件事:我不想多次编写代码。事实上,这是我在编程中真正讨厌的一件事。我想要某个 code/behaviour.

的单一责任来源

对于大多数,好吧,所有 操作 Vector 都有一定的模式。如果我添加两个包含 ints 或 floats 的二维向量并不重要,操作总是相同的。

现在,虽然我天真地想 "Well, how difficult can this be?!" 事实证明,对于我这个 Scala 新手来说,这并不容易。

我开始于:

trait Vector[Vec <: Vector]
{
  def add(v: Vec): Unit
  def subtract(v: Vec): Unit
  def multiply(v: Vec): Unit
  def multiply(s: Numeric): Unit
  def dot(v: Vec): Numeric
  def length(): Numeric
  def distance(v: Vec): Numeric
  def normalise(): Unit
  def divide(length: Numeric): Unit
  def toArray(): Array[Numeric]
}

我的想法:在我继续的过程中添加一个界限会对我有所帮助。

示例:

abstract class Vector2(var x: Numeric, var y: Numeric) extends Vector[Vector2]
{
  override def add(v: Vector2): Unit =
  {
    this.x += v.x
    this.y += v.y
  }
//...
}

然后我想创建如下子类型:

class IntVector2(var x: Int, var y: Int) extends Vector2

并完成它。

问题从这里开始:

abstract class Vector2(var x: Numeric, var y: Numeric) extends Vector[Vector2]
{
  override def add(v: Vector2): Unit =
  {
    this.x += v.x // **here is the problem **
    this.y += v.y
  }
//...
}

它说

Type mismatch, expected: String, actual: Numeric

我认为使用数字作为上限会很聪明,因为我假设会为所有定义一个加法...我错在哪里?

我该如何解决这个问题?有什么想法吗?

此外,在我忘记之前...

假设我需要使用助手的情况,比如 math.sqrt(...)。在那里做什么?

目前(仅针对 float 实施,注意!)我这样做:

def length(): Float =
{
  math.sqrt(x * x + y * y).toFloat
}

现在,如果我想对 doubles 和 ints 使用相同的内容,我怎样才能使它通用?喜欢,没有 .toFloat

此外,我完全知道使用 booleans 我会遇到问题,因为有些操作根本没有定义......我希望没有理由惊慌失措:)

您真的应该考虑深入了解 scala 标准集合库。注意所有以Like结尾的类:TraversableLike、SeqLike、SetLike等。他们使用 higher-order types and typeclass polymorphism。注意所有使用隐式参数的方法,如 def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That.

Here是提供了很多数值抽象的项目,可以作为参考。