2015-10-18 26 views
0

我目前正在考虑重构我的个人线性代数包。 让我困扰的一件事是:实现抽象行为只是一次...特征作为契约,抽象类作为具体帮手

目前我只支持由float s组成的向量和矩阵。现在我想添加支持int s,double s,甚至可能为boolean s,但我必须考虑这一点。

有一件事:我不想多次写代码。事实上,这是我真正讨厌编程的一件事。我想为某个代码/行为提供单一的责任来源。

对于大多数人来说,好吧,全部操作a矢量有一定的模式。如果我添加两个维持int s或float s的二维矢量并不重要,则操作始终是相同的。

现在,天真地我虽然“嗯,这是多难呢?!”对我来说,作为一个Scala-noobie,并不那么容易。

我开始:

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 
    } 
//... 
} 

它说

类型不匹配,预计:字符串,实际:数字

我以为我会很聪明的用数字作为上限,因为我假设一个加法将被定义为所有...我有多么错?

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

另外,我忘了之前...

假设我需要使用一个辅助,像math.sqrt(...)案件。那里做什么?

目前(只实施了float S,心!)我这样做:

现在,如果我想为 double S和 int S也是一样的,我怎么能做出这种通用
def length(): Float = 
{ 
    math.sqrt(x * x + y * y).toFloat 
} 

?等等,而不.toFloat

此外,我充分认识到,与boolean的I会得到一个问题,因为一些操作只是不是在所有定义......没有理由惊慌,我希望:)

回答

1

你应该真的考虑寻找内部scala标准收藏库。注意以结尾的所有课程,如:TraversableLike,SeqLike,SetLike等。他们使用higher-order typestypeclass polymorphism。注意所有使用隐式参数的方法,如def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That

Here是提供许多数字抽象并可以用作参考的项目。

+0

事实上,我想避免暗示,直到我真的,真正了解他们。它们就像我的黑匣子。 – Sorona

+0

有一个可悲的事实:没有它们的scala真棒收藏库不可能如此真棒。你不需要在任何地方忽略所有其他表达手段,因为它没有形状(和其他haskell灵感库)所做的。但有时他们是不可或缺的 – ayvango