object App {
def main(args: Array[String]) {
println(test(1, fun1)) // result is 1
println(test(1, fun2)) // result is 1, too
}
def test(i: Int, fun: Int => Int) = fun(i)
// function fun1
def fun1(i: Int) = i
// function fun2
def fun2 = (i: Int) => i
}
这两个函数传递给test
函数,并输出相同的结果。
fun1
和fun2
的区别是什么?
答案 0 :(得分:4)
在Scala术语中,您的代码表达了两个方法。如果我们分析代码语义,这两种方法将为任何给定的输入产生相同的输出。意思是,对于任何两个相等的域,这些方法将生成相同的范围值。
如果我们从编译器的角度来看它们,那么两者的不同之处在于前者需要Int
并返回Int
,而后者则不会参数并返回Function1[Int, Int]
类型的函数,它本身需要Int
并返回Int
。从逻辑上讲,您可以将其视为Function0[Function1[Int, Int]]
(如果您在REPL中调用fun2 _
,则可以看到它),但实际上它只是fun2
的调用。
为了编译前者,编译器执行 eta-expansion ,将方法转换为函数。我们可以通过scalac
的一点标志来看到这一点:
def main(args: Array[String]): Unit = {
scala.this.Predef.println(scala.Int.box(App.this.test(1, {
{
(new <$anon: Function1>(): Function1)
}
})));
scala.this.Predef.println(scala.Int.box(App.this.test(1, App.this.fun2())))
};
我们还可以看到为前者创建的自动生成的类转换为实际的Function1[Int, Int]
对象:
@SerialVersionUID(value = 0) final <synthetic> class $anonfun$fun2$1 extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
def <init>(): <$anon: Function1> = {
$anonfun$fun2$1.super.<init>();
()
};
final def apply(i: Int): Int = $anonfun$fun2$1.this.apply$mcII$sp(i);
<specialized> def apply$mcII$sp(i: Int): Int = i;
final <bridge> <artifact> def apply(v1: Object): Object = scala.Int.box($anonfun$fun2$1.this.apply(scala.Int.unbox(v1)))
}
答案 1 :(得分:1)
简而言之,这就是:
println(test(1, fun1)) // result is 1
- &GT;
// fun1 is a method which takes one argument,
// but we are using it without arguments, so
// it must be a partial application
// and test expects a function,
// so let's convert it to a function
val res0 = (x: Int) => fun1(x)
val res1 = test(1, res0)
println(res1)
VS
println(test(1, fun2)) // result is 1, too
- &GT;
// fun2 takes no arguments, so it's a valid call
// and its return type is consistent with test expectations
val res0 = fun2() // () are optional in Scala
val res1 = test(1, res0)
println(res1)
<强>更新强>
您可以使用_
:
scala> fun1 _
res0: Int => Int = $$Lambda$1435/1367214620@3db13b89
答案 2 :(得分:0)
以下是它们如何不同的示例 - 我添加了类型注释以使事情变得清晰并安抚编译器。
假设:
trait T {
def fun(i: Int) : Int
}
第一个定义编译:
object A extends T {
// fun1 equivalent
override def fun(i: Int) : Int = i
}
但第二个不是:
//error: object creation impossible,
//since method fun in trait T of type (i: Int)Int is not defined
object B extends T {
// fun2 equivalent
// error: method fun overrides nothing.
override def fun : Int => Int = (i: Int) => i
}
有关详细信息,请参阅其他答案。