函数子类型和Scala-混淆
所以我对函数子类型有点困惑。我有下面这个我正在胡闹的东西。相反,我知道A->Int是B->Int的一个子类型,这就是为什么我能够将AToInt分配给“testBContra” 但我想我能做的是将一个对象传递给“testBContra” testBContra(a) 这不管用。我是否误解了可以传递的信息?我想我现在可以传递一个对象,让它返回一个Int函数子类型和Scala-混淆,scala,Scala,所以我对函数子类型有点困惑。我有下面这个我正在胡闹的东西。相反,我知道A->Int是B->Int的一个子类型,这就是为什么我能够将AToInt分配给“testBContra” 但我想我能做的是将一个对象传递给“testBContra” testBContra(a) 这不管用。我是否误解了可以传递的信息?我想我现在可以传递一个对象,让它返回一个Int class S(x: Int) { val sInput = x } class A(x: Int) extends S(x){ val
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)
testBContra
具有类型B=>Int
,但由于A
不是B
的子类型,因此无法评估testBContra(A)
。当您将函数a=>Int
分配给类型为B=>Int
的值时,使用函数类型的逆变,就像您在中所做的那样
val testBContra: B => Int = AToInt
参数类型为逆变型,结果类型为协变型。相反的意思是,如果A
是B
的超类型,那么对于某些结果类型T
,函数A=>T
是函数B=>T
的子类型。反向反转超级/子类型关系的方向。这意味着如果您有一个函数:
def foo(f: B => Int)
您可以使用AtoInt
直接调用它,因为A=>Int
是B=>Int
的子类型,即
foo(AToInt)
foo((b: B) => AToInt(b))
如果没有函数参数的逆变,则必须在参数类型为B
的函数中包装AToInt
,即
foo(AToInt)
foo((b: B) => AToInt(b))
函数返回类型的协方差意味着,如果B
是a
的子类型,那么对于某些输入类型T
,函数T=>B
是a
的子类型。在您的示例中,由于Int
是AnyVal
和Any
的子类型,AToInt
是a=>AnyVal
和a=>Any
的子类型。如果你有一个函数
def bar(f: A => AnyVal) = f(new A())
然后您可以调用bar(AToInt)
这两种方差可以组合在一起,例如
AToInt
也是B=>AnyVal
的一个子类型,因为a
是B
的一个超类型,Int
是AnyVal的一个子类型,这也有助于了解testBContra
可以做什么。假设它是val testBContra:B=>Int=\uu.bInput
。显然,如果类型系统允许您将类型a
的值a
传递给它,那么类型系统就不健全,因为a
没有方法bInput
。谢谢大家。对不起,如果我在这件事上说得太多了。可能我只是编写了一个糟糕的示例,但是如何才能将a=>Int的内容传递给testBContra呢?函数需要一个对象,因此当我尝试向它传递函数时,它会返回一个error@cpd1-为什么要将函数a=>Int
分配给类型为B=>Int
的变量,然后尝试用a
的实例调用它?你不能直接打电话吗?你能给你的问题添加更多的细节来说明你为什么需要这样做吗?我对这件事有点困惑,如果我不清楚的话,很抱歉,但我只是想向自己证明我可以将a=>Int传递给B=>Int。我想我可以传递对象a,但我意识到我只是在测试类子类型,而不是函数子类型。在我看来,在将类型A=>Int分配给函数之后,我并没有做太多使testBContra工作有任何不同的事情。@cpd1-在分配testBContra
时,您已经将一个函数A=>Int
分配给了类型为B=>Int
的函数。testBContra
和AToInt
之间的区别在于,您正在将参数类型从A
缩小为它的一个子类型B
。这就是为什么您不能将A
传递给testBContra
,即使您可以传递给底层方法。这本身并没有多大用处,但是如果你有一些函数foo(f:B=>Int)
你需要在你已经有一个函数a=>Int
时调用它,就像你在这里做的那样。然后您可以执行foo(AToInt)
而不是foo(b:b=>AToInt(b))