1

私はこのscalaコードを持っています:

class Creature {
  override def toString = "I exist"
}

class Person(val name: String) extends Creature {
  override def toString = name
}

class Employee(override val name: String) extends Person(name) {
  override def toString = name
}

class Test[T](val x: T = null) {

  def upperBound[U <: T](v: U): Test[U] = {
    new Test[U](v)
  }

  def lowerBound[U >: T](v: U): Test[U] = {
    new Test[U](v)
  }
}

Creature、Person、および Employee の間の階層関係を確認できます。

Creature <- Person <- Employee

デフメインで:

val test = new Test[Person]()

val ub = test.upperBound(new Employee("John Derp")) //#1 ok because Employee is subtype of Person
val lb = test.lowerBound(new Creature())            //#2 ok because Creature is supertype of Person

val ub2 = test.upperBound(new Creature())           //#3 error because Creature is not subtype of Person
val lb2 = test.lowerBound(new Employee("Scala Jo")) //#4 ok? how could? as Employee is not supertype of Person

私が理解できることは次のとおりです。

  1. A <: Bdefine A はサブタイプであるか、B と等しい必要があります (上限)

  2. A >: Bdefine A はスーパータイプであるか、B と等しい必要があります (下限)

しかし、#4はどうなりましたか?なぜエラーが出ないのですか?Employee は Person のスーパータイプではないため、バインドされた type parameter に準拠するべきではないと思います[U >: T]

誰でも説明できますか?

4

2 に答える 2

2

この例は役立つかもしれません

scala> test.lowerBound(new Employee("Scala Jo"))
res9: Test[Person] = Test@1ba319a7

scala> test.lowerBound[Employee](new Employee("Scala Jo"))
<console>:21: error: type arguments [Employee] do not conform to method lowerBound's type parameter bounds [U >: Person]
              test.lowerBound[Employee](new Employee("Scala Jo"))
                             ^

一般に、これはLiskov Substitution Principleに関連しています - スーパータイプの代わりにどこでもサブタイプを使用できます (または「サブタイプは常にそのスーパータイプにキャストできます」Person)。

したがって、 ub2 では と の間にそのような交差はありませんが、 lb2 では[Nothing..Person]との間に[Creature..Any]1 つあり、それがです。したがって、ここでの型推論を避けるために、型を明示的に ( の代わりに force で) 指定する必要があります。[Person..Any][Employee..Any]PersonEmployee[Employee..Any]

型推論でも lb2 が失敗すると予想される例:

scala> def aaa[T, A >: T](a: A)(t: T, a2: A) = t
aaa: [T, A >: T](a: A)(t: T, a2: A)T

scala> aaa(new Employee(""))(new Person(""), new Employee(""))
<console>:19: error: type arguments [Person,Employee] do not conform to method aaa's type parameter bounds [T,A >: T]
              aaa(new Employee(""))(new Person(""), new Employee(""))
              ^

ここで、型Aは最初のパラメーター リスト内で推論され、 として固定されるEmployeeため、2 番目のパラメーター リスト (エラーをスローします) は、そのまま使用するしかありません。

または、 invariant で最も一般的に使用される例O[T]:

scala> case class O[T](a: T)
defined class O

scala> def aaa[T, A >: T](t: T, a2: O[A]) = t
aaa: [T, A >: T](t: T, a2: O[A])T

scala> aaa(new Person(""), O(new Employee("")))
<console>:21: error: type mismatch;
 found   : O[Employee]
 required: O[Person]
Note: Employee <: Person, but class O is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
              aaa(new Person(""), O(new Employee("")))
                                   ^

Tはここに固定されており、デフォルトでは不変性の Employeeためキャストできません。O[Employee]O[Person]

于 2015-01-21T12:00:48.343 に答える
1

私はあなたがPersonあなたの

Test[Person].lowerBound(Person)

そのEmployeeサブクラスであるため、ここではどちらが正当であるPersonと見なされます。Person

于 2015-01-19T12:15:18.927 に答える