函数定义与使用
定义函数最通用的方法是作为某个类或者对象的成员,这种函数被称为方法。
其定义的基本语法为:
def 方法名(参数列表):结果类型方法体}
字面量包括整数字面量、浮点数字面量、布尔型字面量、字符字面量、字符串字面量、符号字面量、函数字面量和元组字面量
除了函数字面量我们会比较陌生以外,其他几种字面量都很容易理解
函数字面量可以体现函数式编程的核心理念
在函数式编程中,函数是“头等公民”,可以像任何其他数据类型一样被传递和操作,也就是说,函数的使用方式和其他数据类型的使用方式完全一致了
● 这时,我们就可以像定义变量那样去定义一个函数,由此导致的结果是,函数也会和其他变量一样,开始有“值”
就像变量的“类型”和“值”是分开的两个概念一样,函数式编程中,函数的“类型”和“值”也成为两个分开的概念,函数的“值”,就是“函数字面量”
下面一点点引导大家更好地理解函数的“类型”和“值”的概念
现在定义一个大家比较熟悉的传统类型的函数,定义的语法和我们之前介绍过的定义“类中的方法”类似(实际上,定义函数最常用的方法是作为某个对象的成员,这种函数被称为方法):
上面定义个这个函数的“类型”如下:
实际上,只有多个参数时(不同参数之间用逗号隔开),圆括号才是必须的,当参数只有一个时,圆括号可以省略,如下:
下面看看如何得到函数的“值”
实际上,我们只要把函数定义中的类型声明部分去除,剩下的就是函数的“值”,如下:
注意:上面就是函数的“值”,需要注意的是,采用“=>”而不是“=”,这是Scala的语法要求
现在,我们再按照大家比较熟悉的定义变量的方式,采用Scala语法来定义一个函数。
声明一个变量时,我们采用的形式是:
照葫芦画瓢,我们也可以按照上面类似的形式来定义Scala中的函数:
从上面可以看出,在Scala中,函数已经是“头等公民”,单独剥离出来了“值”的概念,一个函数“值”就是函数字面量。这样,我们只要在某个需要声明函数的地方声明一个函数类型,在调用的时候传一个对应的函数字面量即可,和使用普通变量一模一样
我们不需要给每个函数命名,这时就可以使用匿名函数,如下:
上面这种匿名函数的定义形式,我们经常称为“Lambda表达式”。
“Lambda表达式”的形式如下:
我们可以直接把匿名函数存放到变量中,下面是在Scala解释器中的执行过程:
实际上,Scala具有类型推断机制,可以自动推断变量类型,比如下面两条语句都是可以的:
所以,上面的定义中,我们可以myNumFunc的类型声明。也就是去掉“Int=>lnt”,在Scala解释器中的执行过程如下:
下面我们再尝试一下,是否可以继续省略num的类型声明,在Scala解释器中的执行过程如下:
可以看出,解释器会报错,因为,全部省略以后,实际上,解释器也无法推断出类型
下面我们尝试一下,省略nun的类型声明,但是,给出myNumFunc的类型声明,在Scala解释器中的执行过程如下:
不会报错,因为,给出了myNumFunc的类型为
“Int=>Int”以后,解释器可以推断出num类型为Int类型。
当函数的每个参数在函数字面量内仅出现一次,可以省略“=>”并用下划线“_”作为参数的占位符来简化函数字面量的表示,第一个下划线代表第一个参数,第二个下划线代表第二个参数,依此类推
高阶函数
高阶函数:当一个函数包含其它函数作为其参数或者返回结果为一个函数时,该函数被称为高阶函数
例:假设需要分别计算从一个整数到另一个整数的“连加和”、“平方和”以及“2的幂次和”
方案一:不采用高阶函数
方案二:采用高阶函数
针对容器的操作
遍历操作
Scala容器的标准遍历方法foreach
简化写法:“list foreach(i=>println(i))”或“list foreach println”
简化写法:
映射操作
映射是指通过对容器中的元素进行某些运算来生成一个新的容器。
两个典型的映射操作是map方法和flatMap方法
map方法(一对一映射):将某个函数应用到集合中的每个元素,映射得到一个新的元素,map方法会返回一个与原容器类型大小都相同的新容器,只不过元素的类型可能不同
flatMap方法(一对多映射):将某个函数应用到容器中的元素时,对每个元素都会返回一个容器(而不是一个元素),然后,flatMap把生成的多个容器“拍扁”成为一个容器并返回。返回的容器与原容器类型相同,但大小可能不同,其中元素的类型也可能不同
过滤操作
过滤:遍历一个容器,从中获取满足指定条件的元素,返回一个新的容器
filter方法:接受一个返回布尔值的函数f作为参数,并将f作用到每个元素上,..将f返回真值的元素组成-一个新容器返回
规约操作
规约操作是对容器元素进行两两运算,将其“规约”为一个值
reduce方法:接受一个二元函数f作为参数,首先将f作用在某两个元素王并返回严个值,然后再将f作用在上严个M返回值和容器的下一个元素上,再返回一个值,依此类推,最后容器中的所有值会被规约为一个值
reduceLeft和reduceRight:前者从左到右进行遍历,后者从右到左进行遍历
fold方法:一个双参数列表的函数,从提供的初始值开始规约。第一个参数列表接受一个规约的初始值,第二个参数列表接受与reduce中一样的二元函数参数
foldLeft和foldRight:前者从左到右进行遍历,后者从右到左进行遍历