函数字面量
常说的字面量有:
整型字面量 val i = 123
浮点型字面量 val i = 3.14
布尔型字面量 val i = true
字符串型字面量 val i = "hello"
字面量可以体现函数式编程的核心理念,函数式编程中,函数是“头等公民”,可以像任何其他数据类型一样被传递和操作,也就是说,函数的使用方式和其他数据类型的使用方式完全一致。通俗来讲,函数可以被当作是数据来使用,即可以为函数指定类型等。
函数的类型和值
传统定义函数格式:
def func(value: Int) :Int = {value += 1} //函数中有int型参数value,函数返回类型为Int
上面定义的函数类型可表示为: (Int) => Int
,也就是输入参数为Int类型,返回值Int类型,若只有输入参数,可以省略括号,即Int => Int
,这样就是体现了函数的“类型”。
那么对于函数的值,可以将函数中定义的类型声明部分去掉,剩下的就是函数的“值”:
(value) => (value += 1)
,注意这个值需要使用 => 表示,而不是=
有了上述概念,我们就能清楚地明白函数的类型和值的关系,并能够将其剥离出来。
一般我们声明变量时:
val a : Int = 5 //其中Int是类型,5是值
那么同样可以声明Scala中的函数:
val b : Int => Int = { (value) => value+=1 } //其中Int => Int是类型,{}中的东西是函数的值,此时b就是一个函数类型了
匿名函数
匿名函数用于快速完成一个函数的定义。
例如:(num : Int) => {num * 2}
这种形式的匿名函数也称作Lambda表达式。其基本格式是:
(参数) => 表达式 //若参数只有一个则括号可省略
定义好的匿名函数可以直接将其赋给变量,后面可以直接拿来使用:
val func1 = Int => Int = (num : Int) => num*2 //将匿名函数作为Int => Int函数的值
println(fun1(3)) //可以直接用变量来使用这个匿名函数
我们都知道Scala具有类型推断功能,那么定义的函数也可以像定义变量那样在合适的时候省去类型的指定:
val func1 = Int => Int = {(num:Int) => num*2}
等价于:
val func2 = {(num:Int) => num*2}
闭包
闭包也是一个函数,与普通函数有所区别:
如果定义一个函数中出现了函数中未曾出现的变量名,这个函数就是闭包函数:
val add = (x : Int) => x + y //其中y未在该匿名函数中出现
例如:
var y = 1
val add = (x : Int) => x + y
返回Int = 11
上例中,var y是一个自由变量,他会被绑定到add中的匿名函数里,因此这就体现了一种从变量开放到封闭的过程,因此成为闭包。
注意:每次add函数被调用时都会创建新的闭包,而不是保留原始内存栈空间。
每个闭包都会访问闭包创建时活跃的y变量:
var y = 1
val add = (x : Int) => x + y
add(10)
-->返回Int = 11
y = 2
add(10)
-->返回Int = 12
y = 5
add(10)
-->返回Int = 15
占位符
为了让函数字面量更加简洁,可以使用下划线作为一个或多个参数的占位符,只要每个参数在函数字面量内仅出现一次。
val list1 = List(1,2,3,4,5)
list1.filter(x => x >3) //lambda表达式
list1.filter(_ > 3) //这种写法与上面的写法是一样的
有时候希望使用把下划线当作是参数的占位符,单是编译器可能并不认识,例如:
val f = _+_
运行时会报错,因为编译器推断不出来类型。
应为占位符参数指定类型: val f = (_:Int) + (_:Int)
网友评论