我想要这个类型:
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) = ???