2011-09-08 124 views
3

我已阅读Difference between method and function in Scala和许多关于方法和功能差异的文章。我感觉'方法'只是一个被定义为类,特质或对象中方法的“命名函数”。一个'函数'代表这些文章中的“匿名函数”或“函数文字”或“函数对象”之类的东西。一个证据可以在Scala编程http://www.artima.com/shop/programming_in_scala_2ed,第141页第8.1节中找到,“定义函数的最常见方法是作为某个对象的成员,这样的函数称为方法。”命名方法和命名函数的定义是什么?

但是,当我检查斯卡拉语言参考http://www.scala-lang.org/docu/files/ScalaReference.pdf时,有像命名方法的概念。在页91,第6.20节返回表达式:“一个返回表达式返回e必须发生在一些名为 方法或函数的正文内部。”您也可以在同一页面和其他地方找到术语“命名的功能”。

所以我的问题是,在斯卡拉,方法,命名方法和命名函数是指同一个概念?你在哪里得到命名函数的定义?

在代码List(1, 2).map(_ + 1)中,原始表达式_ + 1是一个命名方法,然后将该方法转换为函数。什么样的函数,匿名函数,函数对象,命名函数?在我的理解,斯卡拉只有两种类型的函数:一个命名函数是一种方法;一个函数文字的匿名函数。函数文字被编译到特征函数N的函数对象中,以便它在纯粹的面向Scala的面向对象世界中使用。

但是,对于上述代码中的常规命名函数/方法(例如_ + 1),为什么Scala会将其转换为另一个函数对象?

回答

6

在语言级别,只有两个概念,

  • 方法是斯卡拉的基本构建块。方法是总是命名。方法生活在课堂或特征中。方法是JVM的本地构造,因此在Scala和Java中都是相同的。在斯卡拉(不同于功能)的方法可能具有特殊的功能:它们可以在类型参数中抽象出来,他们的观点可以有默认值或者是隐式的,等等

  • 函数对象只是一个功能特征的情况下(Function1Function2,...)。该函数在调用函数对象的apply方法时进行评估。定义未命名的“匿名”函数(又名“函数文字”)有特殊的语法。函数只是一个值,因此可以命名(例如,val f: (Int => Int) = (x => x))。 A => B的类型是Function1[A, B]的简写。

linked SO question,有人提到一些参考(如Scala的规范)使用词“功能”不精确为是指“方法”或“功能对象”。我想部分原因是方法可以自动转换为函数对象,这取决于上下文。然而请注意,相反的转换是没有意义的:一种方法不是一个一流的值,它以自己的独立存在存在于堆上。相反,一种方法与它所定义的类别有着千丝万缕的联系。

+0

函数 - >方法转换是不可避免的,所讨论的方法是在函数类中定义的“应用”。非常像我的原始拳击比喻:) –

+0

我会说不同:每个函数*代表一个函数类的实例上定义的'apply'方法。这里没有转换,这就是函数的定义。另一方面,将一个方法转换为一个函数实际上是分配和构建新的东西。 –

+0

我问过这个问题,因为方法和函数的混合使我困惑 - 是一种函数方法吗?或命名的功能?或者根本不是功能?这个答案使用了最后一个定义,即一个方法不是一个函数。这个定义在Scala语言规范中是不成立的(参见上面的问题)。这是我试图澄清的事情。 – Ying

7

到链接的问题盖的回答这个还算不错,但要满足您的特定查询:

  • 方法=>事情你与def关键字定义
  • 命名方法=>同样的,所有方法的名称为
  • 命名函数=>已分配给值或从方法转换的函数。与匿名函数形成对比。

方法和函数之间的区别有点像Java中的int基元和盒装Integer之间的区别。

在一般的讨论中,听到两者都被描述为“整数”是很常见的。这通常不是问题,但是您必须注意确定区别是否与有关。

同样,当你的程序需要它的时候,一个方法会自动转换成一个Function(因此也是一个对象),就像装箱一个原语一样。所以这不是完全错误,指的是作为一种功能的方法。

UPDATE

那么它是怎样工作的?

当您尝试将方法作为参数传递给例如List[A].map,编译器将生成一个派生Function1[A,B]的内部类(具有合成名称)和一个委托给最初提供的方法的apply方法。这个实例将作为实际参数传递。

+0

用于“int”/“Integer”比较的+1。 –

+0

拳击比较帮助。我知道Scala需要将函数字面量转换为FunciontN的方法,因为Scala是一种OO语言。但是,如果您提供map为常规对象方法,为什么Scala会将方法“框”到另一个方法中? – Ying

+0

一个方法永远不会被“装箱”到另一个方法中,而只会被放入一个函数中。当您将方法指定为例如'List [A] .map',它实际上是作为函数'A => B'传递的。在内部,map方法将在提供的函数实例上调用'apply',然后调用您指定的方法。 –