我想有一个通用的矢量抽象类/特征来指定某些方法,例如:
trait Vec
{
def +(v:Vec):Vec
def *(d:Double):Vec
def dot(v:Vec):Double
def norm:Double
}
我想让
Vec2D
和Vec3D
扩展Vec
:class Vec2D extends Vec { /* implementation */ }
class Vec3D extends Vec { /* implementation */ }
但是,例如,如何使
Vec2D
只能添加到其他Vec2D
而不能添加到Vec3D
?现在,我只是在没有通用
Vec2D
祖先的情况下实现Vec3D
和Vec
,但这在重复代码中变得乏味。我必须实施依赖于这些类的所有几何类(例如Triangle
,Polygon
,Mesh
,...)两次,一次用于Vec2D
,另一次用于Vec3D
。我看到了Java实现:
javax.vecmath.Vector2d
和javax.vecmath.Vector3d
没有共同的祖先。这是什么原因呢?有没有办法在scala中克服它? 最佳答案
作为requested,设计基本特征的最有用的方法涉及到CRTP和self-type annotation。
trait Vec[T <: Vec[T]] { this: T =>
def -(v: T): T
def *(d: Double): T
def dot(v: T): Double
def norm: Double = math.sqrt(this dot this)
def dist(v: T) = (this - v).norm
}
如果没有自类型,则无法调用
this.dot(this)
,因为dot
期望使用T
;否则,将无法调用norm
。因此我们需要通过注释来强制执行。另一方面,没有CRTP,我们将无法在
(this - v)
上调用-
,因为T
返回T
,因此我们需要确保类型T
具有此方法,例如声明Vec[T]
是。