Scala 上界和下界的理解
Understanding of Upperbound and Lowerbound in Scala
我有这个 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 main 中:
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
我能理解的是:
A <: B
定义 A 必须是子类型或等于 B(上限)
A >: B
定义 A 必须是超类型或等于 B(下限)
但是#4 怎么了?为什么没有错误?由于 Employee 不是 Person 的超类型,我希望它不符合绑定类型参数 [U >: T]
.
谁能解释一下?
我认为这是因为您可以将任何 Person
传递给您的
Test[Person].lowerBound(Person)
并且由于 Employee
是 Person
的子类,所以它被认为是 Person
,在这里是合法的。
这个例子可能有帮助
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 - 你可以在任何地方使用子类型而不是超类型(或 "subtype can always be casted to its supertype"),所以类型推断试图尽可能地推断出最接近的超类型(如 Person
这里)。
因此,对于 ub2,[Nothing..Person]
和 [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]
由于默认不变性。
我有这个 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 main 中:
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
我能理解的是:
A <: B
定义 A 必须是子类型或等于 B(上限)A >: B
定义 A 必须是超类型或等于 B(下限)
但是#4 怎么了?为什么没有错误?由于 Employee 不是 Person 的超类型,我希望它不符合绑定类型参数 [U >: T]
.
谁能解释一下?
我认为这是因为您可以将任何 Person
传递给您的
Test[Person].lowerBound(Person)
并且由于 Employee
是 Person
的子类,所以它被认为是 Person
,在这里是合法的。
这个例子可能有帮助
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 - 你可以在任何地方使用子类型而不是超类型(或 "subtype can always be casted to its supertype"),所以类型推断试图尽可能地推断出最接近的超类型(如 Person
这里)。
因此,对于 ub2,[Nothing..Person]
和 [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]
由于默认不变性。