1

次のクラス定義を検討してください。

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]]

関連する以前の質問How to define case classes with members with unbound type parameters?に対する Daniel C. Sobral の回答に感謝します。ここでは、実存型がそのトリックを行うことを知っています。これはコンパイルされます:

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

<: Person[T]この問題は、クラス Person の宣言の型パラメーターの上限によって引き起こされます。上限を削除すると、コンパイラーはリストの型パラメーターを推測してコンパイルList[Person[Person[Person[Any]]]]できるようになります。

質問

  1. コンパイラは、リストをコンパイルするタイプを推論できないのはなぜですか?
  2. 存在型は冗長性が最も低く、さらにトリッキーになる可能性があります (上記の私の以前の質問に対するダニエルの回答を参照してください): 学生と教授のリストを作成するための明示的な存在型に代わるものはありますか?
4

1 に答える 1

1

2番目のコメントで、可能な代替案について言及したと思います

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-language で、型パラメーターと抽象型メンバーの統合について考えていると述べました。

実際のユースケースに応じて、最も簡単な解決策はメソッドのオーバーライドに依存することです。

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)
于 2012-04-26T07:41:33.673 に答える