F-bounded多态 - 常见的超类型不遵循类型边界

时间:2016-01-29 15:41:08

标签: scala generics types

我正在尝试使用强类型行数据访问来建模类似于集合的集合。我正在使用F-bounded多态(递归类型)模式,以便通过转换携带表类型信息(例如,访问DataView中的列列表是表过滤的结果)。只要使用实际类型,一切正常。请查看下面的代码片段,了解有问题的常见超类型操作。

inferred type arguments [DataTable[_2]] do not conform to method dump's type parameter bounds [A <: DataTable[A]]
found: DataTable[_2] where type _2 >: Table1 with Table2 <: DataTable[_ >: Table1 with Table2 <: Object]

最后一行产生编译错误:

for(counter | test | action){}

似乎自我类型边界不会保留在替代Table1和Table2的类型中。是否有任何已知的解决方法?

更新: 如果我错了,请纠正我,但我认为我错误地认为Table1和Table2有共同的超类型,它具有DataTable的特征。它们具有DataTable [_]的常见超类型,但这不再是有效的DataTable - 这正是scala编译器试图告诉我的内容:)。

确实可以尝试使用存在类型,但是引入GenericDataTable类型作为DataTable [A]的基础可以更直接的方式解决问题。

在我的情况下 - 遗憾的是,这并不容易 - 因为它需要构建互连类的另一个赞美层次结构。

的Marcin

2 个答案:

答案 0 :(得分:0)

我自己也想了解了一些问题:

getTable的返回类型是:

def getTable(name: String): DataTable[_ >: Table1 with Table2 <: DataTable[_ >: Table1 with Table2]]

实际上是DataTable[_]

以下代码也失败了:

val tbl: DataTable[_] = new Table1
dump(tbl)

由于转储期望DataTable的某个特定子类型,并且它得到其抽象类型DataTable[_],因此很有意义。

所以,如果具体的子类型隐藏在它的抽象超类型后面,我怀疑F-bounded是否有意义:如果输入类型是DataTable[_],如果你能推断出特定的子类型,我会感到惊讶它背后的对象是静态的。

由于getTables可以返回更多类型的DataTable,因此其返回类型可能不会比DataTable[_]更具体。确实在这方面工作是最有希望的途径,但评论中建议的解决方案不是编译:

def getTable(name: String): A forSome { type A <: DataTable[A] }
编辑:我做到了!这很奇怪!:

type DataTableSubtype = A forSome {type A <: DataTable[A]}
def convertToSubtype(tbl:DataTableSubtype): DataTableSubtype = tbl
def getTable(name: String): DataTableSubtype = {
  name match {
    case "Table1" => {convertToSubtype(new Table1)}
    case "Table2" => {(new Table2())}
  }
}

dump(getTable("Table1"))

诀窍是强制至少一个返回的表格为A forSome {type A <: DataTable[A] 类型!因此,各种子类型对象的工厂可以公开返回对象的具体类型!我不得不说,心灵不好。

我必须指出转储可能只是:

def dump(table: DataTable[_]): Unit

当输入类型也是我们在第一时间使用F-bounded类型的返回类型时,例如:

def id[A <: DataTable[A]](table: A): A = table

因为这会使我们无法获取Table1并返回Table2。

总而言之,F-bounded方法(这是创建F-bound类型的动机)在输入类型是F-bounded的具体子类型时有意义类型,类型在返回类型中使用,直接用作A或间接用作Something[A]

答案 1 :(得分:0)

这是catch-22的scala版本。

你已经省略了返回类型,scala默默地错误计算它并给出你无关的错误。

万恶之源: DataTable[_]不是定义为DataTable[A <: DataTable[A]]的F-bounded类型的正确存在类型它是DataTable[A] forSome {type A <: Any} <的简写em> F-bound 在这里丢失了。正确的类型是DataTable[A] forSome { type A <: DataTable[A] }

Scala的不当行为:当有疑问时,类型检查器会将类型推断为类似DataTable[_]的类型。好吧,它的精确度稍高,但仍然在失去 F-bound

所以答案是定义正确的类型并明确指定它:

object DataTable {
  type Any = DataTable[A] forSome {type A <: DataTable[A]}
}

def getTable(name: String) : DataTable.Any = // fill here