Scala函数和方法比较

关于function和method,Scala规范中给出抽象的定义,理解它有助于深度领悟scala的编程思想,也能体会到function和method的本质区别。
首先要理清几个名词的关系:函数声明(Function declaration),函数值(Function value),方法类型(Method type)和方法值(Method value)。

函数声明 = 方法类型 + 函数体(表达式或者代码块)。重要的是,函数声明也就是方法(method),方法类型是它的组成部分,它给出了方法的描述(包括方法名和签名),但它不会直接执行。
Method = Function declaration = method type + body
Method type = just define method without value

函数类型定义了大量的函数抽象,用于生成函数值,而函数值就是函数(function)。函数类型本质是trait,它包含一个抽象apply方法,如下。

函数包括了匿名函数和方法值,而方法类型可以转换为方法值。
Function type = trait FunctionN with apply method
Function value = function = object instantiated by a class extends from FunctionN.

上面的描述是理论基础,在scala实践中函数(function)和方法(method)也是不同的。
函数本质是对象,是实现了 FunctionN trait的类的实例。Scala提供了各种不同参数数量的trait,如Function0,Function1…。而方法属于定义范畴,只有在调用的时候才会执行。
函数使用val定义,而方法使用def定义。所以函数在定义的时候就会执行,并开辟内存空间,大量的函数必定会产生内存问题,而方法则是在每次调用的时候才会执行。可以见函数更像一个变量,而方法则属于定义,更多用在类中实现功能。
方法可以转换为函数,而函数却不能转换为方法。方法转函数的方法是[method type] _,如下代码。

如上所说,函数是实例化的对象,所以它是有方法的,而方法则没有。

对于方法转函数,它的本质就是生成实例化的trait对象,所以每次执行会开辟不一样的内存空间,生成不同的对象。

Scala为函数的定义和调用提供了语法糖(Syntactic sugar),简化了函数的语法,当然也可以用完整的函数来定义和调用。如下代码,可以用lamda表达式来定义函数,也可以自己实现Function trait定义函数;可以用括号()来调用函数,也可以用apply方法调用函数,他们的效果是一样的。

方法支持类型参数(type-parameterized),即不指明参数的数据类型(可变类型),而函数语法糖不支持,因为函数要立刻执行,必须明确参数类型,而方法在调用的时候才会执行,此时指定参数是可以接受的。

如果函数想支持可变类型参数,必须自己实现trait,而不能使用lamda表达式。

函数定义可以有两种方式,一种是上面演示的匿名函数(anonymous function, 可以叫 => lamda表达式,也可以叫function literals),另一种是使用类型签名(type signature),如下代码。

参考:
http://jim-mcbeath.blogspot.com.au/2009/05/scala-functions-vs-methods.html
https://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#default-arguments
https://www.scala-lang.org/files/archive/spec/2.11/03-types.html#function-types

Scala函数和方法比较