Function 什么';这两种结构的根本区别是什么?

Function 什么';这两种结构的根本区别是什么?,function,scala,anonymous-function,Function,Scala,Anonymous Function,可能重复: scala>valx1:(Int)=>Int=(x)=>x+1 x1:(Int)=>Int= scala>defx2(x:Int)=x+1 x2:(Int)Int scala>x1(1) res0:Int=2 scala>x2(1) res1:Int=2 x1和x2之间的实际差异是什么。你能举例说明什么时候使用这两种结构吗?在Scala中,这两种结构从用户的角度看很相似,但从JVM的角度看却完全不同x1是一个“函数对象”,而x2是一个方法 代码示例 方法 在Scala中,def定

可能重复:

scala>valx1:(Int)=>Int=(x)=>x+1
x1:(Int)=>Int=
scala>defx2(x:Int)=x+1
x2:(Int)Int
scala>x1(1)
res0:Int=2
scala>x2(1)
res1:Int=2

x1和x2之间的实际差异是什么。你能举例说明什么时候使用这两种结构吗?

在Scala中,这两种结构从用户的角度看很相似,但从JVM的角度看却完全不同
x1
是一个“函数对象”,而
x2
是一个方法

代码示例 方法 在Scala中,
def
定义了一个直接编译成JVM方法的方法,它必须属于某个Java类

在上面的代码片段中,
x2
x3
都被编译为JVM方法,并且属于
类测试
,甚至
x3
都是在方法(嵌套方法)中定义的

编译代码后,您可以使用
javap-private Test
验证这一点。它将输出以下梅萨日:

brianhsu@USBGentoo ~/test $ javap -private Test
Compiled from "test.scala"
public class Test extends java.lang.Object implements scala.ScalaObject{
    private final scala.Function1 x1;
    public scala.Function1 x1();
    public int x2(int);
    private final int x3$1(int);
    public Test();
}
您可以看到,
x2
只是一个普通的Java方法,并且x3被重命名为x3$1(以避免在other method`中存在另一个
x3
时出现名称冲突),但从JVM的角度来看,它仍然是一个普通的Java方法

函数对象 我使用这个术语是为了避免混淆,这是您用
valx1=(x:Int)=>x+1
之类的东西定义的

当您使用它时,它可能看起来像方法,但实际上它与您使用
def
s定义的方法完全不同

那么
valx1=(x:Int)=>x+2
意味着什么

在Scala中,有一些特性称为Function0、Function1、Function2、Function3……Function22

它看起来都是这样的(我简化了它):

当您编写
valx1=(x:Int)=>x+2
时,Scala编译器将生成一个实现trait函数1的对象,它可能如下所示:

val t = new Function1[Int, Int] { 
    def apply(t1: Int) = t1 + 2
}
当您编写
x1(3)
时,实际上Scala只是将其转换为t.apply(3)

因此,函数对象不是方法,它只是一个普通的Java对象,它有一个名为
apply
的方法,Scala编译器为您提供了一种语法糖,在使用它们时不必显式调用
apply

您可以再次使用
javap
来验证这一点

brianhsu@USBGentoo ~/test $ javap Test\$\$anonfun\$1 
Compiled from "test.scala" public final class Test$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp implements scala.Serializable{
    public static final long serialVersionUID;
    public static {};
    public final int apply(int);
    public int apply$mcII$sp(int);
    public final java.lang.Object apply(java.lang.Object);
    public Test$$anonfun$1(Test); 
}

brianhsu@USBGentoo ~/test $ javap -private Test 
Compiled from "test.scala" public class Test extends java.lang.Object implements scala.ScalaObject{
    private final scala.Function1 x1;
    public scala.Function1 x1();
    public int x2(int);
    private final int x3$1(int);
    public Test(); 
}
您会注意到有一个名为
Test$$anonfun$1.class
的额外.class文件,它是
(x:Int)=>x+2
的类,您会注意到有一个
x1
私有变量,它是
Function1
的类型,a
x1()
方法返回
scala.Function1

x1()
方法,因为Scala实现了统一的访问原则。但是最重要的是
x1()
方法只返回
Test$$anonfun$1
类的函数对象实例

结论 也许方法和函数看起来是一样的,但它们是不同的东西。Scala编译器可以帮助我们不费吹灰之力地同时使用它们

大多数情况下,您不会关心它们之间的区别,但确实有时有些东西需要一个函数对象,而您只有方法

在这种情况下,编译器会告诉您,在方法名之后添加一个
,将其提升到函数对象

更新 下面是一个有趣的代码示例,显示了方法和函数对象之间的差异:您可以定义一个包含25个参数的方法,但不能定义包含22个以上参数的函数对象

class Test2
{
    def x (
      x01: Int, x02: Int, x03: Int, x04: Int, x05: Int,
      x06: Int, x07: Int, x08: Int, x09: Int, x10: Int,
      x11: Int, x12: Int, x13: Int, x14: Int, x15: Int,
      x16: Int, x17: Int, x18: Int, x19: Int, x20: Int,
      x21: Int, x22: Int, x23: Int, x24: Int, x25: Int
    ) = 0

    // Compile error: 
    //  implementation restricts functions to 22 parameters

    /*
    val y = (
      x01: Int, x02: Int, x03: Int, x04: Int, x05: Int,
      x06: Int, x07: Int, x08: Int, x09: Int, x10: Int,
      x11: Int, x12: Int, x13: Int, x14: Int, x15: Int,
      x16: Int, x17: Int, x18: Int, x19: Int, x20: Int,
      x21: Int, x22: Int, x23: Int, x24: Int, x25: Int
    ) => 0
    */
}

它的答案几乎涵盖了一切。我认为如果你把它看作是一种对象上的方法,这确实很有帮助,但我也能理解为什么有些人会不同意这种观点。更多的是:这个问题已经被问了很多次,但人们从来没有找到问题,因为他们不知道区别是什么,所以他们不知道如何提问。第一个是函数,第二个是方法。知道了这一点,就去读他们之间的区别。@Jonas,那是不对的
x1
是一个函数,
x2
是一个方法。为什么要否决投票?我是否误解了他们之间的区别?
val t = new Function1[Int, Int] { 
    def apply(t1: Int) = t1 + 2
}
brianhsu@USBGentoo ~/test $ javap Test\$\$anonfun\$1 
Compiled from "test.scala" public final class Test$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp implements scala.Serializable{
    public static final long serialVersionUID;
    public static {};
    public final int apply(int);
    public int apply$mcII$sp(int);
    public final java.lang.Object apply(java.lang.Object);
    public Test$$anonfun$1(Test); 
}

brianhsu@USBGentoo ~/test $ javap -private Test 
Compiled from "test.scala" public class Test extends java.lang.Object implements scala.ScalaObject{
    private final scala.Function1 x1;
    public scala.Function1 x1();
    public int x2(int);
    private final int x3$1(int);
    public Test(); 
}
class Test2
{
    def x (
      x01: Int, x02: Int, x03: Int, x04: Int, x05: Int,
      x06: Int, x07: Int, x08: Int, x09: Int, x10: Int,
      x11: Int, x12: Int, x13: Int, x14: Int, x15: Int,
      x16: Int, x17: Int, x18: Int, x19: Int, x20: Int,
      x21: Int, x22: Int, x23: Int, x24: Int, x25: Int
    ) = 0

    // Compile error: 
    //  implementation restricts functions to 22 parameters

    /*
    val y = (
      x01: Int, x02: Int, x03: Int, x04: Int, x05: Int,
      x06: Int, x07: Int, x08: Int, x09: Int, x10: Int,
      x11: Int, x12: Int, x13: Int, x14: Int, x15: Int,
      x16: Int, x17: Int, x18: Int, x19: Int, x20: Int,
      x21: Int, x22: Int, x23: Int, x24: Int, x25: Int
    ) => 0
    */
}