更多Scala打字问题

时间:2011-05-26 16:14:20

标签: scala types

既然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() ...

2 个答案:

答案 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 {
  ...
}

存在感可能很棘手,如果可能的话,最好避免使用。