Mad*_*doc 5 generics scala scala-2.8
在下文中,我将仅提供我的Scala代码的非常简化版本.足以显示问题.不必要的代码块将减少到....
我创建了一个矢量库(也就是说,用于建模数学矢量,而不是意义上的矢量scala.collection.Vector).基本特征如下:
trait Vec[C] extends Product {
def -(o:Vec[C]):Vec[C] = ...
...
}
Run Code Online (Sandbox Code Playgroud)
我已经为特定的载体创建了许多子类型,比如Vec2二维向量,或Vec2Int专门用于二维Int向量.
子类型缩小了某些操作的返回类型.例如,Vec2Int从另一个向量中减去a 将不会返回泛型Vec[Int],但更具体Vec2Int.
另外,我已经在非常特定的子类型中声明了这些方法,例如Vec2Intas final,从而允许编译器选择那些用于内联的方法.
这非常有效,我已经为矢量计算创建了一个快速且可用的库.
在此基础上,我现在想要创建一组类型来模拟基本的几何形状.基本的形状特征如下:
trait Shape[C, V <: Vec[C]] extends (V=>Boolean) {
def boundingBox:Box[C,V]
}
Run Code Online (Sandbox Code Playgroud)
在哪里Box是Shapen维盒子的子类型.
现在,我试图定义框:
trait Box[C, V <: Vec[C]] extends Shape[C,V] {
def lowCorner:V
def highCorner:V
def boundingBox = this
def diagonal:V = highCorner - lowCorner // does not compile
}
Run Code Online (Sandbox Code Playgroud)
该diagonal方法无法编译,因为该方法Vec.-返回Vec[C],而不是V.
当然,我可以diagonal退货Vec[C],但这在很多方面都是不可接受的.这一次,我将失去特定Vec子类型的编译器优化.此外,例如,当你有一个由两个二维Float向量(Vec2Float)描述的框时,假设对角线也是一个很有意义Vec2Float.我不想丢失这些信息.
按照Scala集合层次结构的示例,我介绍了一个类型VecLike:
trait VecLike[C, +This <: VecLike[C,This] with Vec[C]] {
def -(o:Vec[C]):This
...
}
Run Code Online (Sandbox Code Playgroud)
我做了Vec扩展:
trait Vec[C] extends Product with VecLike[C, Vec[C]] ...
Run Code Online (Sandbox Code Playgroud)
(然后我会继续创建更多特定的子类型VecLike,比如Vec2Like或者Vec3Like,以支持我的Vec类型层次结构.)
现在,新的定义Shape和Box看起来像这样:
trait Shape[C, V <: VecLike[C,V] with Vec[C]] ...
trait Box[C, V <: VecLike[C,V] with Vec[C]] extends Shape[C,V] {
...
def diagonal:V = highCorner - lowCorner
}
Run Code Online (Sandbox Code Playgroud)
仍然,编译器抱怨:
Error: type mismatch;
found: Vec[C]
required: V
Run Code Online (Sandbox Code Playgroud)
这让我很困惑.类型VecLike清楚地返回This在负方法,转化为类型参数V的的Box类型.我可以看到Vec仍然返回的减去方法Vec[C],但为什么此时编译器不能使用返回类型VecLike的减号方法?
我该如何解决这个问题?
我的建议是在省略你认为无关的代码时更加努力,只显示代码.人们经常设法删除重要的部分真是太神奇了.口头禅是"如果你不知道为什么它不起作用,那么你就不知道什么是相关的." 这是非常认真的,真实的建议:如果你给我编译的代码除了你不理解的东西外,我可以在五秒钟内给你帮助,或者如果我必须重建你所有的碎片,我可以在五分钟内帮助你遗漏了 猜猜哪一个经常发生.
关于代码.在我猜测第一次尝试的位如何填充到第二次尝试之后,它完全按照给定的方式编译.(这个"猜测"阶段是预先显示代码的另一个好理由.)
trait VecLike[C, +This <: VecLike[C, This] with Vec[C]] {
def -(o: Vec[C]): This
}
trait Vec[C] extends Product with VecLike[C, Vec[C]] { }
trait Shape[C, V <: VecLike[C,V] with Vec[C]] { }
trait Box[C, V <: VecLike[C,V] with Vec[C]] extends Shape[C, V] {
def lowCorner: V
def highCorner: V
def boundingBox = this
def diagonal: V = highCorner - lowCorner
}
% scalac281 a.scala
%
Run Code Online (Sandbox Code Playgroud)