为什么executeCommand
接受错误返回类型的callBack
函数?
import scala.sys.process._
object Test {
def executeCommand(x: String)(y: Int => Unit) = {
def matchStrToInt(str: String) = {
str match {
case "true" => 1
case "false" => 2
}
}
y(matchStrToInt(x))
} //> executeCommand: (x: String)(y: Int => Unit)Unit
executeCommand("true")(callBack)
def callBack(x: Int): Int = {
x
} //> callBack: (x: Int)Int
}
据我所知,Scala是严格的静态类型语言。 有人可以解释其背后的原因吗?
答案 0 :(得分:4)
我认为这里发生的事情是Scala编译器中的两个独立机制正在协同工作:
这基本上只是一种避免在每次()
是预期类型时必须明确写入Unit
Unit
值的方法。就像在while
循环结束时,Unit
返回方法,for(a <- list){ ... }
表达式等
它重写(在编译期间在内存中,而不是在磁盘上)这样的代码
def foo: Unit = 42
到这个
def foo: Unit = { 42; () }
这就是Scala中的方法转换为函数的方式。方法是JVM构造,是JVM类文件的元素。函数只是一个值,是scala.FunctionN
类的一个实例。您可以将函数作为值传递(因为它们是值),但您不能将方法作为值传递(因为它们不是)。
基本上,编译器会进行以下转换:
def foo(i: Int): Int = i
def bar(f: Int => Int) = f
bar(foo)
~~~>
bar( (x1: Int) => foo(x1) )
所以当你有这个代码时:
def foo(i: Int): Int = i
def bar(f: Int => Unit) = f
bar(foo)
编译器将首先使用eta扩展将foo
转换为函数。
bar( (x1: Int) => foo(x1) )
然后它会看到foo(x1)
是Int
类型的表达式,而在那里预期类型为Unit
的表达式。所以它将适用价值丢弃。
bar( (x1: Int) => { foo(x1); () } )
您可以检查只有在将方法转换为函数时才会出现此“问题”:
scala> def bar(f: Int => Unit) = f
bar: (f: Int => Unit)Int => Unit
scala> val foo = (i: Int) => i
foo: Int => Int = <function1>
scala> bar(foo)
<console>:14: error: type mismatch;
found : Int => Int
required: Int => Unit
bar(foo)
^