Scala类的协方差在可衍生类型的参数



我想要这个类型:

abstract class Model[U](val query: TableQuery[ModelTable[U]]) {
    // ...
}

但是在查询类型中有协方差

这个想法是我有一个函数,它接受U的一个实例,并且需要访问相应的TableQuery[ModelTable[U]]的一个实例。添加类型参数很麻烦,因为我不能再使用上下文边界编写函数:

def f[U : Mode](u: U) = // ...

和每次写出隐式参数是相当麻烦的。就目前而言,我不明白为什么这是不可能的。给定U的具体类型,查询的类型约束对于编译器来说应该是微不足道的。

可能更具体:为什么不能编译:

// error: Unbound Wildcard Type
abstract class Model[U](val query: _ <: TableQuery[ModelTable[U]]) {
    // ...
}

query参数已经协变。你的问题好像是这样的:

class TableQuery[T]
class TableQuerySub[T] extends TableQuery[T]
class ModelTable[T]
class ModelTableSub[T] extends ModelTable[T]
class Model[U](val query: TableQuery[ModelTable[U]])
val x1: TableQuerySub[ModelTable[Int]] = ???
val x2: TableQuery[ModelTableSub[Int]] = ???
new Model(x1)
new Model(x2) // does not compile

这里x2不编译以下消息:

type mismatch;
found : TableQuery[ModelTableSub[Int]]
required: TableQuery[ModelTable[?]] 
Note: ModelTableSub[Int] <: ModelTable[?], 
but class TableQuery is invariant in type T. 
You may wish to define T as +T instead. (SLS 4.5)

这里编译器告诉我们它不确定TableQuery[ModelTableSub[_]]扩展了TableQuery[ModelTable[_]]。为了告诉编译器确实是这种情况,我们需要将TableQuery的参数设置为协变

class TableQuery[+T]

如果这对你没有帮助,请在你的问题中包括用例。


编辑

添加第二个类型参数仍然允许您指定上下文绑定。上下文绑定语法只不过是语法糖。以下语句是相等的:

def f[U : Model](u:U) = {
  val m = implicitly[Model[U]]
  ???
}
def f[U](u:U)(implicit m:Model[U]) = ???

有了这些知识,我们可以为有多个参数的上下文添加上下文边界:

class Model2[A, B]
def f[U](u:U)(implicit m:Model[_, U]) = ???

如果你真的想使用上下文绑定语法来指定它,你可以这样做

type AnyModel2[B] = Model2[_, B]
def f[U : AnyModel2](u:U) = ???

如果没有类型别名,你会得到(在我看来可读性较差)

def f[U : ({type T[x] = Model2[_, x]})#T](u:U) = ??? 

最新更新