Scala类型成员差异

Ale*_*rov 8 scala variance higher-kinded-types

考虑这个简短的片段:

trait Table[+A] {
  type RowType = Seq[A]
}
Run Code Online (Sandbox Code Playgroud)

Scala 2.11.7编译器给出以下错误:

covariant type A occurs in invariant position in type Seq[A] of type RowType
Run Code Online (Sandbox Code Playgroud)

为什么被A认为处于不变的位置,Seq[A]Seq它本身被定义为trait Seq[+A]

另外,如果我们忽略错误,您能否提供一个用例来说明此类型定义可能存在的问题?

Odo*_*ois 10

对于任何B <: ATable[B]#RowType将更具体的Table[A]#RowType.更具体并不意味着相同,因此编译器将类型别名的参数视为不变位置.

你怎么能解决这个问题.

抽象成员

您可以将类型定义为抽象,这意味着您应该稍后定义它并且可能会遇到相同的问题,但是在trait Table级别上这样的定义将是正确的

trait Table[+A] {
  type RowType <: Seq[A]
}
Run Code Online (Sandbox Code Playgroud)

混凝土高级型

您可以定义参数化类型成员,这可能会导致更改您使用此类型的方式,但在大多数情况下应该完成这项工作.

trait Table[+A] {
  type RowType[+X] = Seq[X]
}
Run Code Online (Sandbox Code Playgroud)

关于类型成员差异

不是我最强的领域,但我试着描述我的想法.

假设你有

trait Table[+A] {
  type RowType = Seq[A]
}

def mkTable[A]: Table[A]  = new Table[A] {}
Run Code Online (Sandbox Code Playgroud)

然后你做了以下

val tupleTable = mkTable[(String, String)]
val prodTable: Table[Product] = tupleTable 
Run Code Online (Sandbox Code Playgroud)

那会是prodTable.RowType什么?

如果你的定义应该是Seq[Product].但是等等,prodTable并且tupleTable是同一个对象,所以他们的成员应该是相同的,所以prodTable.RowType应该是Seq[(String, String)]

但是如果你改成第一种方法就好了

trait Table[+A] {
  type RowType <: Seq[A]
}

def mkTable[A]: Table[A]  = new Table[A] {
  type RowType = Seq[A]
}
Run Code Online (Sandbox Code Playgroud)

编译器会知道RowTypeTable[Product]是某种类型的<: Seq[Product]这是真的Seq[(String, String)],所有ambiguilties都不见了.