Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
函数子类型和Scala-混淆_Scala - Fatal编程技术网

函数子类型和Scala-混淆

函数子类型和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

所以我对函数子类型有点困惑。我有下面这个我正在胡闹的东西。相反,我知道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 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))