scala函数的定义格式如下:
def functionName(params): resultType={
functionBody
}
scala函数的基本构成和java方法是基本一样的,只是格式上相差比较大。以def关键字开始函数定义,然后是函数名和括号中的参数列表,冒号“:”和函数的返回类型(scala中称为结果类型:result type),接着是等号“=”,最后是方法体。
参数的格式是(param: type),如果没有返回类型,可以不写,或者用Unit,类似于java中的void。
以下是一个例子:
def add(x: Int, y: Int): Int = {
x+y
}
只有一个句子组成,也可以写成这样
scala> def add(x: Int, y: Int): Int =x+y
其实,当函数是类/对象的成员时,这种函数称为方法:method。为了区分函数,接下来,把def定义的函数称为方法。(现实中,也可以这么认为)
在函数式编程语言中,函数是“头等公民”,它可以像任何其他数据类型一样被传递和操作函数可以作为一个参数传递到方法中。
像值一样可以进行参数传递到方法中的函数叫做函数文本(function literal)。
函数文本的语法很简单:右箭头左边是参数列表,右边是函数体,如下
(x: Int, y: Int)=>x+y
函数文本被编译进一个类,在运行期是一个函数值(function value),所以可以存为变量,或者常量,并且可以作为函数来调用。
scala> val add=(x:Int, y: Int)=>x+y
add: (Int, Int) => Int =
scala> add(2,3)
res0: Int = 5
List的foreach()方法的参数就是一个函数文本,它可以用来做遍历。如下:
scala> val lst=List(1,3,5)
lst: List[Int] = List(1, 3, 5)
scala> lst.foreach((i:Int)=>println(i))
1
3
5
这就是scala的一个特征,函数式风格编程,然后scala还可以把函数文本写得更简短
lst.foreach(i=>println(i))
因为编译器可以从lst知道i的类型,所以可以把函数文本的参数类型省掉,这叫做目标类型化(target typing)。并且,参数的括号也可以去掉。
使用占位符”_”可以让函数进一步简洁
scala> lst.foreach(println (_))
或者
scala> lst.foreach(println _) //注意println和”_”之间有空格
可以理解为把lst每次取出的元素替换掉下划线进行println操作。仅当每个参数在函数文本中最多出现一次的情况下才能使用这种短格式。多个下划线指代多个参数,而不是单个参数的重复使用。
其实函数最后可以简洁到不用下划线,
scala> lst.foreach(println)
这个要解释的话就要引出一个概念,偏应用函数(partially applied function),注意不是偏函数。
scala>def add(a:Int, b:Int)=a+b
add: (a:Int, b: Int)Int
通过在add后面加下划线,将方法转成函数,add _称为偏应用函数表达式。
scala>val addp=add _
addp:(Int, Int) => Int =
将新的函数值指向变量addp之后,就通过addp来实现add的功能。
scala> val result=addp(2,3)
result: Int = 5
在调用println的时候,就等于调用println _表达式。
最后看一下高阶函数foreach的源码:
def foreach[B](f: A => B) {
var these = this
while (!these.isEmpty) {
f(these.head)
these = these.tail
}
}
isEmpty 判断列表是否为空,head返回列表的第一个元素,tail返回除第一个以外的所有元素组成的列表。
从f(these.head)可以看出,foreach是把函数f运用到列表的每个元素。
比如定义一个函数,打印出每个后面加上$符号的数字。
scala> val printDols=(num: Int, symbol:String)=>println(num+symbol)
printDols: (Int, String) => Unit =
scala>lst.foreach(printDols(_,"$"))
1$
3$
5$