什么';Scala中两个函数的区别是什么?
这两个函数传递到什么';Scala中两个函数的区别是什么?,scala,Scala,这两个函数传递到test函数,并输出相同的结果 fun1和fun2有什么区别 在Scala术语中,您的代码表示两种方法。如果我们从语义上分析代码,这两个方法将为任何给定的输入产生相同的输出。这意味着,对于任意两个相等的域,这些方法将产生相同的值范围 如果我们从编译器的角度来看,这两个函数的不同之处在于前者接受Int并返回Int,而后者不接受参数并返回类型为Function1[Int,Int]的函数,函数本身接受Int并返回Int。从逻辑上讲,您可以将其视为Function0[Function1[
test
函数,并输出相同的结果
fun1
和fun2
有什么区别 在Scala术语中,您的代码表示两种方法。如果我们从语义上分析代码,这两个方法将为任何给定的输入产生相同的输出。这意味着,对于任意两个相等的域,这些方法将产生相同的值范围
如果我们从编译器的角度来看,这两个函数的不同之处在于前者接受Int
并返回Int
,而后者不接受参数并返回类型为Function1[Int,Int]
的函数,函数本身接受Int
并返回Int
。从逻辑上讲,您可以将其视为Function0[Function1[Int,Int]]
(如果您在REPL中调用fun2
,您可以看到它),但实际上它只是调用fun2
为了让前者编译,编译器执行eta扩展,将方法转换为函数。我们可以通过scalac
的一个小标志看到这一点:
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
}
简而言之,发生的事情如下:
@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)))
}
->
vs
->
更新
您可以通过使用\uu
将方法显式转换为函数:
// 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
第一个定义包括:
trait T {
def fun(i: Int) : Int
}
但第二种情况并非如此:
object A extends T {
// fun1 equivalent
override def fun(i: Int) : Int = i
}
有关详细信息,请参见其他答案。因此,对
fun2
的引用是一个方法调用,而对fun1
的引用是一个简单的名称访问。@Elazar不确定“简单名称访问”是什么意思。对fun2
的调用是对Function0[Function1[Int,Int]]
的简单调用,其中对fun1
的调用必须扩展以创建具体的类实例。这两者之间有明确的区别。您只需引用方法的名称即可。就像引用任何其他变量一样。@Elazar为了“仅仅引用”方法的名称,编译器必须根据命名方法的求值进行一些欺骗。正如您的代码片段所示,fun2
不会被转换为Function0[Function1[Int,Int]]
。当您使用fun2
作为test
Scala中的参数时,Scala将简单地对其求值,即调用方法fun2
它需要哪种返回类型。我不确定此示例试图显示什么?语义相同并不意味着语法相同,正如我在回答中解释的那样。如果你的回答是为了说明这些方法在语法上是相同的,我想他知道。@YuvalItzchakov这些定义是不等价的。“语法相同”意味着“相同的程序文本”,这里当然不是这样。语义上,第一个声明覆盖trait的声明,而另一个不覆盖。OP想要知道的是它是否重要,将定义哪一个。答案是“是”,这里举例说明。你关于语义等价的回答是指定义函数的行为。我的回答(以及op的问题)涉及到定义本身。我的回答试图解决这两种方法的语义行为和编译器的解释,仅此而已。如果你认为这个答案对OP的问题有不同的解释,很好,那么OP从不同的角度得到了另一个答案。
// 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
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
}