【问题标题】:Scala class with covariance in derivable type of parameter在可派生参数类型中具有协方差的 Scala 类
【发布时间】:2014-09-12 11:15:43
【问题描述】:

我想要这个类型类:

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]]) {
    // ...
}

【问题讨论】:

  • 你能举一个类型类实例的例子吗?我不确定我是否理解您想要实现的目标。
  • 这或多或少是您想要的吗?抽象类 Model[U, T <: tablequery query: t ... class modeltable>
  • 是的,但是如上所述,额外的类型参数不是我理想的解决方案,因为现在我不能将模型实例视为类型类的实例。

标签: scala generics types covariance


【解决方案1】:

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) = ??? 

【讨论】:

  • 您对编译器抱怨的参数是正确的。我解决了如下; abstract class Model[U](val query: TableQuery[_ &lt;: ModelTable[U]]) { ... } 这是允许的。但我对“为什么”更感兴趣。如果编译器可以推断出这些泛型,为什么上下文边界仅限于具有一个有界泛型的类?
  • 但这可能需要更精细的类型级编程
  • 啊,感谢您的洞察力。我没有考虑过使用通配符的类型别名的可能性。我想这就是我一直在寻找的。我知道上下文限制为隐式,但正如问题中所述:写出隐式非常繁重。更是如此,因为我已经有一个隐式会话传递。
猜你喜欢
  • 2019-09-23
  • 1970-01-01
  • 1970-01-01
  • 2021-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-09
  • 1970-01-01
相关资源
最近更新 更多