既然Kim Stebel helped me understanding如何用存在类型键入变量,我需要知道如何在继承中使用它们:
以下代码无法编译:
class PagingListModel(startPageNumber: Int, pageSize: Int, query: Query[Projection[_ <: Product]]) extends AbstractListModel {
val itemStartNumber: Int = startPageNumber * pageSize
val items: List[Product] = getPageData()
override def getPageData(): List[Product] = {
db withSession {
return queryToQueryInvoker(query.drop(itemStartNumber).take(pageSize)).list
}
}
}
...错误:
no type parameters for method queryToQueryInvoker:
(q: org.scalaquery.ql.Query[org.scalaquery.ql.ColumnBase[T]])
org.scalaquery.ql.basic.BasicQueryInvoker[T]
exist so that it can be applied to arguments
(org.scalaquery.ql.Query[org.scalaquery.ql.Projection[_ <: Product]])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : org.scalaquery.ql.Query[org.scalaquery.ql.Projection[_ <: Product]]
required: org.scalaquery.ql.Query[org.scalaquery.ql.ColumnBase[?T]]
...这很奇怪,因为所需的类型确实在找到的类型的范围内...
PS:我真的只想在foreach
返回的列表中的每个元组上调用getPageData()
...
答案 0 :(得分:2)
我不认为这可以用存在类型来完成。它适用于类型参数:
class PagingListModel[T <: Product](... query: Query[Projection[T]]) {
...
def getPageData(): List[_ <: Product] = ...
queryToQueryInvoker(query.drop(itemStartNumber).take(pageSize)).list
}
原始版本是正确的,但由于类似于Haskell的单态限制,Scala无法对其进行类型检查。 queryToQueryInvoker的type参数必须是Scala不支持的通用类型[T <: Product] forAll { type T }
。
通过使用显式类型参数,可以使用该特定类型实例化queryToQueryInvoker。该方法仍然可以返回List[_ <: Product]
,因为List在其元素类型中是共变量。
编辑:毕竟是可能的。你必须将存在主义移动到正确的位置:
class PagingListModel(... query: Query[Projection[T]] forSome { type T <: Product }) {
def getPageData(): List[_ <: Product] = ... {
val i = queryToQueryInvoker(query.drop(itemStartNumber).take(pageSize))
i.list
}
}
如果没有额外的变量i
,编译器将推断错误的类型,然后抱怨它。对我来说看起来像个错误。
答案 1 :(得分:1)
我对ScalaQuery的了解有限,但看起来你应该参数化这个类。
class PagingListModel[T <: Product] (
startPageNumber: Int,
pageSize: Int,
query: Query[Projection[T]]
) extends AbstractListModel {
...
}
存在感可能很棘手,如果可能的话,最好避免使用。