[英]why the first type parameter is defined as contravariant in Function1[-A, +B]?
所有读完Scala协方差/逆变问题及其答案由Daniel Spiewak提供,以及“Scala编程”一书的第19.3-19.7节,我对Function1 [-A,+ B]的定义有另一个疑惑:为什么它的第一种类型参数是逆变的吗? 我有一个原因,就是这个类型参数保证当有多种情况时,子类型总是出现在超类型之前,同时,子类型“是一个”超类型。 例如:
class A
class B extends A
class C extends B
scala> val withDefault: A => B = {
| case x:B => new B
| case x:A => new B }
withDefault: A => B = <function1>
这里,(1) case x:B
早于case x:A
,(2)功能1 [A,B] <:功能1 [B,B]并且必须有其他原因? 任何消息将不胜感激!
逆变性与模式匹配无关。 这就是为什么函数类型在它们的参数类型上是逆变的。 考虑这个功能:
def doHigherOrder(handleAnyAnimal: Animal => T,
anyAnimal: Animal ): T = {
// ...foo...
handleAnyAnimal(anyAnimal)
// ...bar...
}
如果函数是协变而不是逆变,那么函数Duck => T
也将是Animal => T
的子类型,你可以做doHigherOrder(handleAnyDuck)
。 这将是一个错误因为那时,在doHigherOrder
, handleAnyAnimal(anyAnimal)
表达式将(在运行时/评估时)归结为handleAnyDuck(anyAnimal)
,这显然是不对的,因为可以处理任何Duck
的函数可能无法处理任何Animal
:
def doHigherOrder(handleAnyDuck: Duck => T,
anyAnimal: Animal ): T = {
// ...foo...
handleAnyDuck(anyAnimal) // <-- ERROR
// ...bar...
}
此外,假设Creature >: Animal
,函数handleAnyCreature: Creature => T
确实也是Animal => T
的子类型,因为可以将anyAnimal
传递anyAnimal
可以接受anyCreature
东西。
这就是为什么逆变在参数类型中直观上是不可避免的。
但是,返回值是协变的,因为它们具有与值完全相同的语义:
val animal = getDuck() // ok
val duck = getAnimal() // <-- ERROR
与之比较
val x = handleDuck(animal) // <-- ERROR
val y = handleAnimal(duck) // ok
形象地说,你分配给函数参数,但是从它们的返回值。 使用命名参数变得更加明显:
val x = handle(duck = animal) // <-- ERROR
val y = handle(animal = duck ) // ok
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.