Scala类型参数作为内射映射

时间:2018-06-11 18:22:37

标签: scala generics traits implicit type-parameter

有一些类型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技术?

1 个答案:

答案 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的功能是什么。它似乎没有做任何事情。