为实现具有(self)类型参数的类的对象集合键入推断

时间:2012-04-25 20:29:02

标签: scala type-inference scala-collections type-parameter existential-type

考虑以下类定义:

class Person[+T <: Person[T]]
class Student() extends Person[Student]
class Professor() extends Person[Professor]

我想要一份有学生和教授的名单:

val persons = List(new Student(), new Professor())

但是无法使用以下错误进行编译:

type arguments [Person[Person[Any]]] do not conform to class Person's type parameter bounds [+T <: Person[T]]

感谢Daniel C. Sobral回答我之前提到的相关问题How to define case classes with members with unbound type parameters?我知道一个存在主义类型可以解决这个问题。这编译:

val persons = List[Person[T] forSome {type T <: Person[T]}](new Student(), new Professor())

问题是由Person类声明的type参数中的上限<: Person[T]引起的。删除上限允许编译器推断列表的类型参数,使其编译:{{1​​}}就我所见。

问题

  1. 为什么编译器不能推断列表的任何类型会使它编译?
  2. 存在类型是最简单的,也可能更棘手(参见Daniel对上一个问题的回答):是否有替代显式存在类型来创建学生和教授的名单?

1 个答案:

答案 0 :(得分:1)

我相信你在第二条评论中提到了一个可能的替代方案

val persons = List[Person[_]](new Student(), new Professor())

但是根据我的理解,Scala中用于执行此类操作的惯用方法是在Person中使用类型声明并在Student和Professor中定义:

trait Person {
  type PersonImpl <: Person
  def colleagues: Seq[PersonImpl]
}

class Student extends Person {
  type PersonImpl = Student
  def colleagues = Seq(this)
}

class Professor extends Person {
  type PersonImpl = Professor
  def colleagues = Seq(this)
}

val persons = List(new Student, new Professor)

Martin Odersky也用scala语言提到he's thinking about unifying type parameters and abstract type members

根据您的实际用例,最简单的解决方案可能是依赖方法覆盖:

trait Person {
  def colleagues: Seq[Person]
}

class Student extends Person {
  def colleagues: Seq[Student] = Seq(this)
}

class Professor extends Person {
  def colleagues: Seq[Professor] = Seq(this)
}

val persons = List(new Student, new Professor)