scala的函数为什么参数都是逆变的而返回值都是协变的

在scala中,函数特质的定义都是类似下面的:

trait FunctionN[-T1, -T2,-T3...-TN, +R] extends AnyRef

也就是说参数都输逆变的,返回值都是协变的。在scala中,函数是一等公民,他可以像数组(数组也是支持逆变和协变的)被赋值和传参。所以函数必须要被支持赋值操作。如果一个函数要想赋值给另一个函数的指针(无论是直接赋值还是当做函数传参),函数的参数必须是指针(函数的指针)参数相同的类型或者父类型,返回值必须是指针(函数的指针)返回值的相同类型或者子类型。比如说有一个指针f1:

f1 : (Son1) => Father 2 // Son1 extend Father1,Son2 extend Father2

然后有一个函数f2:

f2 : (father1) => son2

现在把f2赋值给f1是没有问题的。

f1 = f2

为什么可以这样?
我们先约定一下称谓。我们把(Son1) => Father 2称作f1的定义类型。当f1被f2赋值后,f1的类型是(father1) => son2 我们称之为f1的运行类型。使用者使用被赋值后的f1时只知道f1的定义类型,而不知道f1的运行类型(只有jvm知道)那我们只会传给被赋值后的f1 Son1类型的参数,也只会把被赋值后的f1的返回值当做Father2来用。其中内在的赋值逻辑就是:

  • 对于参数:f1定义的类型(使用者传给函数的)-> f1运行时的类型
  • 对于返回值:f1运行后的返回值类型 -> f1 定义的返回值类型(使用者希望获得的类型)

假设我们现在要使用f1指向的函数,我们给传个Son1类型的参数,但是实际上f1代表的是f2类型的函数,也就相当于我们把Son1传给(father1) => son2。根据泛型,这当然没有问题。j现在f2的参数是Son1的子类型,那显然是不行的。返回值也是这个道理。

发布了85 篇原创文章 · 获赞 21 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_37275456/article/details/100800452