有一些类型 T
和抽象类 X[T]
,重点是,对于每个具体类型T,如果定义,只有 X[T]
的一个子类,例如 IntX extends X[Int]
,这是 X[T]
与 T = Int
的唯一子类 . 也就是说,理论上我们对某些类型的集合有一个内射映射 T -> X[T]
.
我们来看看两个简单的定义:
trait Context[T] {
type XType <: X[T]
}
abstract class X[T] extends Context[T] {
def plus1(that: XType): XType = ??? /* doesn't matter */
def plus2(that: XType): XType = that plus1 this
def sum(x1: XType, x2: XType): XType = x1.plus1(x2)
}
在这里,我们看到 X[T]
有一些方法 . 为了在具体的继承子类中具有正确的最终类型,我使用 XType
作为从 X[T]
继承的子类的类型 . 例如,像这样:
trait IntContext extends Context[Int] {
type XType = IntX
}
class IntX extends X[Int] with IntContext
然后方法 IntX.plus1
接受 IntX
并返回 IntX
,而不是 X[Int]
,所以这是对相当抽象的例子的简要解释 . Context
用于包含与每个使用类型T相关的类型和结构构造函数的所有信息 . 嗯,有更有意义的 Context
示例,只是为了正确理解事物:
trait Context[V <: ArithmType[V]] { /* V such as Int, Double */
type Point <: AbstractPoint[V]
type Line <: AbstractLine[V]
type Rect <: AbstractRect[V]
...
def newPoint(x: V, y: V): Point
def newLine(v1: Point, v2: Point): Line
def newRect(p: Point, w: V, h: V): Rect
...
def pointCompanion: AbstractPoint.Companion[V]
def lineCompanion: AbstractLine.Companion[V]
def rectCompanion: AbstractRect.Companion[V]
...
}
The problem is:
带有 X[T]
的代码将无法编译 . 当然,如果我们看看最后两种方法,我们会得到以下错误:
Type mismatch, expected: that.XType, actual: X[T]
Type mismatch, expected: x1.XType, actual: X.this.XType
我们看到编译器将每个XType变量实例的自有类型视为彼此不同 . 当然,这是正确的,但编译器不知道的是我们继承的内在性:对于固定类型 T
,所有 XType
类型的值都是相同的 .
我怎么能实现这样的逻辑来绕过这个?
我设计了一个解决方案,但它相当脏 . 重写代码:
trait Context[T] {
type XType <: X[T]
implicit def cast(x: X[T]): XType = x.asInstanceOf(XType)
}
abstract class X[T] extends Context[T] {
def plus1(that: XType): XType = ??? /* doesn't matter */
def plus2(that: XType): XType = that plus1 that.cast(this)
def sum(x1: XType, x2: XType): XType = x1 plus1 x1.cast(x2)
}
没有隐式转换,方法将如下:
def plus2(that: XType): XType = cast(that plus1 that.cast(this))
def sum(x1: XType, x2: XType): XType = cast(x1 plus1 x1.cast(x2))
asInstanceOf
-casting不会失败,因为我们知道我们对注入的限制 . 可以使用模式匹配,但这是细节 .
这个解决方案的主要缺点是需要类代码重构:我们在业务逻辑部分中放置了一些混乱的转换 .
此解决方案是否有权使用?你有什么想法?
Edit: 在这种情况下有没有办法使用 Aux
技术?
1 回答
如果每个
T
总是只有一个具体的子类Repr <: X[T]
,那么这个类Repr
本身就会知道每个其他X[T]
必须是Repr
. 所以,只需将Repr
类型作为X
的参数,就可以在所有plusXYZ
-method声明中使用它:虽然这是有效的,但是有一个警告:所有那些圆形的f-bound-polymorphism特技都会变得相当讨厌 . 类型组合往往组成更好 .
顺便说一下:我不确定上面代码片段中
Context
的功能是什么 . 它似乎没有做任何事情 .