有一些类型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]
...
}
问题是:
带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
- 当我们知道我们对注入性的约束时,施法不会失败。可以使用模式匹配,但这是详细信息。
这个解决方案的主要缺点是需要类代码重构:我们在业务逻辑部分中放置了一些混乱的转换。
此解决方案是否有权使用?你有什么想法?
修改:在这种情况下,有没有办法使用Aux
技术?
答案 0 :(得分:0)
如果每个T
始终只有一个具体的子类Repr <: X[T]
,那么此类Repr
本身就会知道每个其他X[T]
必须是Repr
。因此,只需将类型Repr
作为参数提供给X
,以便它可以在所有plusXYZ
- 方法声明中使用它:
trait Context[T, Repr <: X[T, Repr]]
abstract class X[T, Repr <: X[T, Repr]] extends Context[T, Repr] {
def plus1(that: Repr): Repr = ??? /* doesn't matter */
def plus2(that: Repr): Repr = that plus1 that
def sum(x1: Repr, x2: Repr): Repr = x1 plus1 x2
}
class IntX extends X[Int, IntX]
虽然这有效,但有一个警告:所有那些圆形的f-bounded-polymorphism特技往往会变得相当讨厌。类型组合往往组成更好。
顺便说一下:我不确定上面代码片段中Context
的功能是什么。它似乎没有做任何事情。