函数子类型和Scala - 混淆

时间:2015-12-15 19:05:05

标签: scala

所以我对功能子类型感到困惑。我有下面的内容,我正在搞乱。我知道,对于逆变,A-> Int是B-> Int的子类型,这就是为什么我能够将AToInt分配给" testBContra"。

但我认为我能做的就是将A对象传递给" testBContra" ...

testBContra(a)中

哪个不起作用。我误解了可传递的内容吗?我以为我现在可以传递一个A对象并让它返回一个Int。

class S(x: Int) {
  val sInput = x
}

class A(x: Int) extends S(x){
  val aInput = x
}

class B(x: Int) extends A(x){
  val bInput = x
}

def AToInt(h: A): Int = h.aInput

// Checking contravariance

// val testSContra: S=>Int = AtoInt
val testAContra: A=>Int = AToInt
val testBContra: B=>Int = AToInt

val a = new A(2)
val b = new B(5)
val s = new S(10)

testAContra(b)
testBContra(b)

1 个答案:

答案 0 :(得分:2)

testBContra的类型为B => Int,但由于A不是B的子类型,因此您无法评估testBContra(a)。当您将函数A => Int分配给类型为B => Int的值时,会使用函数类型的逆变量

val testBContra: B => Int = AToInt

Function1 trait在其参数类型中是逆变的,在其结果类型中是协变的。逆变量意味着如果AB的超类型,则函数A => T是某个结果类型B => T的函数T的子类型。逆变性反转超/子类型关系的方向。这意味着如果你有一个功能:

def foo(f: B => Int)

您可以使用AtoInt直接调用它,因为A => IntB => Int的子类型,即

foo(AToInt)

没有函数参数的逆变,你必须将AToInt包装在参数类型为B的函数中,即

foo((b: B) => AToInt(b))

函数返回类型的协方差意味着如果BA的子类型,则函数T => B是某些输入类型{{1}的T => A子类型}}。在您的示例中,由于TIntAnyVal的子类型,AnyAToIntA => AnyVal的子类型。所以,如果你有一个功能

A => Any

然后你可以拨打def bar(f: A => AnyVal) = f(new A())

可以合并两种方差,例如bar(AToInt)也是AToInt的子类型,因为B => AnyValA和{{1}的超类型}是B的子类型。