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

在 def 主目录中:

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 <: B定义 A 必须是子类型或等于 B(上限)

  2. A >: B定义 A 必须是超类型或等于 B(下限)

但是#4 发生了什么?为什么没有错误?由于 Employee 不是 Person 的超类型,我希望它不应该符合绑定类型参数[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 替换原则有关- 您可以在任何地方使用子类型而不是超类型(或“子类型始终可以转换为其超类型”),因此类型推断试图尽可能地推断出最接近的超类型(如Person这里)。

[Nothing..Person]所以,对于 ub2和之间没有这样的交集[Creature..Any],但对于 lb2 来说,[Person..Any][Employee..Any]- 之间有一个,那就是Person。因此,您应该显式指定类型(强制Employee而不是[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,因此第二个参数列表(引发错误)只有选择 - 按原样使用它。

或最常用的不变量示例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)

as EmployeeisPerson它的一个子类被认为Person是合法的。

于 2015-01-19T12:15:18.927 回答