[英]Variance of Scala List map function
我有一个困扰我的问题。 Scala中的List[+A]
是协变的( List[+A]
)
假设我们有以下类:
class A
class B extends A
List[B]
的map
函数采用函数f: B => C
但我也可以使用f: A => C
,它是f: B => C
的子类
这完全有道理。
我目前感到困惑的是, map
函数应该只接受原始函数的超类的函数(因为函数的参数是相反的),这不适用于我给出的示例。
我知道我的逻辑有问题,我想启发一下。
您的错误在于map(f: A => C)
应该只接受A => C
超类的函数。
实际上, map
可以接受A => C
的子类的任何函数。
在Scala中,函数参数始终可以是所需类型的子类。
的协方差A
在List[A]
仅告诉你,只要一个List[A]
是必需的,则可以提供一个List[B]
只要B <: A
。
或者,用更简单的话来说: List[B]
可以被视为List[A]
的子类。
我整理了一个小例子来解释这两种行为:
class A
class B extends A
// this means: B <: A
val listA: List[A] = List()
val listB: List[B] = List()
// Example 1: List[B] <: List[A]
// Note: Here the List[+T] is our parameter! (Covariance!)
def printListA(list: List[A]): Unit = println(list)
printListA(listA)
printListA(listB)
// Example 2: Function[A, _] <: Function[B, _]
// Note: Here a Function1[-T, +R] is our parameter (Contravariance!)
class C
def fooA(a: A): C = ???
def fooB(b: B): C = ???
listB.map(fooB)
listB.map(fooA)
我希望这有帮助。
正如您已经怀疑的那样,您在这里混淆了一些事情。
一方面,您有一个List[+A]
,它告诉我们有关List[A]
和List[B]
之间关系的一些信息,给定A
和B
之间的关系。 这样的事实List
是协变A
只是意味着List[B] <: List[A]
当B <: A
,你知道已经知道了。
另一方面, List
公开了一个方法map
以更改其“内容”。 此方法实际上并不关心List[A]
,而仅关心A
s,因此List
的方差在这里无关紧要。 令您感到困惑的是,确实有一些子类型需要考虑: map
接受一个参数(在这种情况下为A => C
,但实际上并不相关),并且像往常一样,对于方法和函数,您始终可以用其子类型的任何内容替换其参数。 在您的特定情况下,只要AcceptedType <: Function1[A,C]
,任何AcceptedType
都可以。 这里重要的方差是Function
的,而不是List
的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.