只实现一次抽象行为...将特征作为契约,抽象 class 作为具体助手
Implement abstract behaviour just once... trait as contract, abstract class as concrete-helper
我目前正在考虑重构我的个人线性代数包。
真正困扰我的一件事是:
目前我只支持由 float
组成的向量和矩阵。现在我想添加对 int
s、double
s 甚至 boolean
s 的支持,但我必须考虑一下。
有一件事:我不想多次编写代码。事实上,这是我在编程中真正讨厌的一件事。我想要某个 code/behaviour.
的单一责任来源
对于大多数,好吧,所有 操作 Vector 都有一定的模式。如果我添加两个包含 int
s 或 float
s 的二维向量并不重要,操作总是相同的。
现在,虽然我天真地想 "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
}
现在,如果我想对 double
s 和 int
s 使用相同的内容,我怎样才能使它通用?喜欢,没有 .toFloat
此外,我完全知道使用 boolean
s 我会遇到问题,因为有些操作根本没有定义......我希望没有理由惊慌失措:)
您真的应该考虑深入了解 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是提供了很多数值抽象的项目,可以作为参考。
我目前正在考虑重构我的个人线性代数包。 真正困扰我的一件事是:
目前我只支持由 float
组成的向量和矩阵。现在我想添加对 int
s、double
s 甚至 boolean
s 的支持,但我必须考虑一下。
有一件事:我不想多次编写代码。事实上,这是我在编程中真正讨厌的一件事。我想要某个 code/behaviour.
的单一责任来源对于大多数,好吧,所有 操作 Vector 都有一定的模式。如果我添加两个包含 int
s 或 float
s 的二维向量并不重要,操作总是相同的。
现在,虽然我天真地想 "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
}
现在,如果我想对 double
s 和 int
s 使用相同的内容,我怎样才能使它通用?喜欢,没有 .toFloat
此外,我完全知道使用 boolean
s 我会遇到问题,因为有些操作根本没有定义......我希望没有理由惊慌失措:)
您真的应该考虑深入了解 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是提供了很多数值抽象的项目,可以作为参考。