《Kotlin从小白到大牛》第14章:函数式编程基石——高阶函数和Lambda表达式
第14章 函数式编程基石——高阶函数和Lambda表达式
函数式编程思想虽然与面向对象一样立即悠久,但是支持函数式编程的计算机语言不过是近几年的事情。这些语言有Swift、Python、Java 8和C++11等,作为新生的语言Kotlin也支持函数式编程。本章将介绍Kotlin语言中函数式编程最重要的基础知识——高阶函数和Lambda表达式。
14.1 函数式编程简介
函数式编程(functional programming)与面向对象编程一样都一种编程范式,函数式编程,也称为面向函数的编程。在函数式编程中一切都是函数。
函数式编程核心概念如下:
o 函数是“一等公民”:是指函数与其他数据类型是一样的,处于平等的地位。函数可以作为其他函数的参数传入,也可以作为其他函数的返回值返回。
o 使用表达式,不用语句:函数式编程关心的输入和输出,即:参数和返回值。在程序中使用表达式可以有返回值,而语句没有。例如:控制结构中的if和when结构都属于表达式。
o 高阶函数:函数式编程支持高阶函数,所谓高阶函数就是一个函数可以作为另外一个函数的参数或返回值。
o 无副作用:是指函数执行过程会返回一个结果,不会修改外部变量,这就是“纯函数”,同样的输入参数一定会有同样的输出结果。
Kotlin语言支持函数式编程,提供了函数类型、高阶函数和Lambda表达式。
14.2 高阶函数
函数式编程的关键是高阶函数的支持。一个函数可以作为另一个函数的参数,或者返回值,那么这个函数就是“高阶函数”。本节介绍一下高阶函数。
14.2.1 函数类型
Kotlin中每一个函数都有一个类型,称为“函数类型”,函数类型作为一种数据类型与数据类型在使用场景没有区别。可以声明变量,也可以作为其他函数的参数或者其他函数的返回值使用。
现有如下3个函数的定义:
//代码文件:chapter14/src/com/a51work6/section2/ch14.2.1.kt
package com.a51work6.section2
//定义计算长方形面积函数
//函数类型(Double, Double) -> Double
fun rectangleArea(width: Double, height: Double): Double { ①
return width * height
}
//定义计算三角形面积函数
//函数类型(Double, Double) -> Double
fun triangleArea(bottom: Double, height: Double) = 0.5 * bottom * height ②
fun sayHello() { //函数类型()->Unit ③
print(“Hello, World”)
}
fun main(args: Array) {
val getArea: (Double, Double) ->Double = ::triangleArea ④ //调用函数 val area = getArea(50.0, 40.0) ⑤ print(area) //1000.0
}
上述代码中,函数rectangleArea和triangleArea具有相同的函数类型(Double, Double) -> Double。函数类型就是把函数参数列表中的参数类型保留下来,再加上箭头符号和返回类型,形式如下:
参数列表中的参数类型 -> 返回类型
每一个函数都有函数类型,即便是函数列表中没有参数,以及没有返回值的函数也有函数类型,如代码第③行的sayHello()函数,sayHello()函数的函数类型是()->Unit。
14.2.2 函数字面量
函数类型可以声明的变量,那么函数类型变量能够接收什么的数据呢?即函数字面量如何表示的问题,函数字面量可以有三种表示:
函数引用。引用到一个已经定义好的,有名字的函数。它可以作为函数字面量。
匿名函数。没有名字的函数,即匿名函数,它也可以作为函数字面量。
Lambda表达式。Lambda表达式是一种匿名函数,可以作为函数字面量。
示例代码如下:
//代码文件:chapter14/src/com/a51work6/section2/ch14.2.2.kt
package com.a51work6.section2
fun calculate(opr: Char): (Int, Int) -> Int {
//加法函数 fun add(a: Int, b: Int): Int { return a + b } //减法函数 fun sub(a: Int, b: Int): Int { return a - b } val result: (Int, Int) -> Int = when (opr) { '+' -> ::add ① '-' -> ::sub ② '*' -> { //乘法匿名函数 fun(a: Int, b: Int):Int { ③ return (a * b) } } else -> { a, b ->(a / b) } //除法Lambda表达式 ④ } return result
}
fun main(args: Array) {
val f1 = calculate(’+’) ⑤
println(f1(10, 5)) //调用f1变量 ⑥
val f2 = calculate(’-’)
println(f2(10, 5))
val f3 = calculate(’*’)
println(f3(10, 5))
val f4 = calculate(’/’)
println(f4(10, 5))
}
上述代码第①行和第②行是函数引用,采用“双冒号加函数名”形式引用,add和sub是两个局部函数,它们的函数引用表示方式是::add和::sub,它们可以作为函数字面量赋值给result变量。代码第③行声明匿名函数,匿名函数不需要函数名,它是一个表达式直接赋值给result变量。代码第④行采用的Lambda表达式,也可以赋值给result变量。
获得一个函数类型的变量之后如何使用呢?答案是可以把它当作函数一样调用。例如代码第⑤行val f1 = calculate(’+’)中f1是一个函数类型变量,事实上f1就是指向add函数的。代码第⑥行是调用f1函数类型变量,事实上就是在调用add函数。其他的变量以此类推,不再赘述。
14.2.3 函数作为另一个函数返回值使用
可以把函数作为另一个函数的返回值使用,那么这个函数属于高阶函数。14.2.2节的calculate函数的返回类型就是(Int, Int) -> Int函数类型,说明calculate是高阶函数。下面再介绍一个函数作为另一个函数返回值使用的示例:
//代码文件:chapter14/src/com/a51work6/section2/ch14.2.3.kt
package com.a51work6.section2
fun getArea(type: String): (Double, Double) -> Double { ①
var returnFunction: (Double, Double)-> Double ② when (type) { "rect" -> //rect 表示长方形 returnFunction =::rectangleArea ③ else -> //tria 表示三角形 returnFunction =::triangleArea ④ } return returnFunction ⑤
}
fun main(args: Array) {
//获得计算三角形面积函数 var area: (Double, Double) ->Double = getArea("tria") ⑥ println("底10 高13,计算三角形面积:${area(10.0,15.0)}") ⑦ //获得计算长方形面积函数 area = getArea("rect") ⑧ println("宽10 高15,计算长方形面积:${area(10.0,15.0)}") ⑨
}
上述代码第①行定义函数getArea,其返回类型是(Double, Double) -> Double,这说明返回值是一个函数类型。第②行代码声明returnFunction变量,显式指定它的类型是(Double, Double) -> Double函数类型。第③行代码是在类型type为rect(即长方形)的情况下,把rectangleArea函数引用赋值给returnFunction变量,这种赋值之所以能够成功是因为returnFunction类型是(Double, Double) -> Double函数类型。第④行与第③行代码一样不再解释。第⑤行代码将returnFunction变量返回。
代码第⑥行和第⑧行调用函数getArea,返回值area是函数类型变量。第⑦行和第⑨行中的area(10,15)调用函数其参数列表是(Double, Double)。
上述代码运行结果如下:
底10 高15,计算三角形面积:75.0
宽10 高15,计算长方形面积:150.0
14.2.4 函数作为参数使用
作为高阶函数还可以接收另一个函数作为参数使用。下面来看一个函数作为参数使用的示例:
//代码文件:chapter14/src/com/a51work6/section2/ch14.2.4.kt
package com.a51work6.section2
//高阶函数,funcName参数是函数类型
fun getAreaByFunc(funcName: (Double, Double) -> Double, a: Double, b:
Double): Double { ①
return funcName(a, b)
}
fun main(args: Array) {
//获得计算三角形面积函数 var result = getAreaByFunc(::triangleArea,10.0, 15.0) ② println("底10 高15,计算三角形面积:$result") ③ //获得计算长方形面积函数 result = getAreaByFunc(::rectangleArea, 10.0,15.0) ④ println("宽10 高15,计算长方形面积:$result") ⑤
}
上述代码第①行定义函数getAreaByFunc,它的第一个参数funcName是函数类型(Double, Double) -> Double,第二个和第三个参数都是Double类型。函数的返回值是Double类型,是计算几何图形面积。
代码第②行是调用函数getAreaByFunc,给它传递的第一个参数::triangleArea是函数引用,第二个参数是三角形的底边,第三个参数是三角形的高。函数的返回值result是Double,是计算所得的三角形面积。
第③行也是调用函数getAreaByFunc,给它传递的第一个参数::rectangleArea是函数引用,第二个参数是长方形的宽,第三个参数是长方形的高。函数的返回值result也是Double,是计算所得的长方形面积。
上述代码的运行结果如下:
底10 高15,三角形面积:75.0
宽10 高15,计算长方形面积:150.0
综上所述,比较本节与上一节的示例,可见它们具有相同的结果,都使用了函数类型(Double, Double)
-> Double,通过该函数类型调用triangleArea和rectangleArea函数来计算几何图形面积。上一节是把函数作为函数返回值类型使用,而本节是把函数作为另一个函数的参数使用。经过前文的介绍,你会发现函数类型也没有什么难理解的,与其他类型的用法一样。
14.3 Lambda表达式
14.2.2节已经使用到了Lambda表达式,Lambda表达式是一种匿名函数,可以作为表达式、函数参数和函数返回值使用,Lambda表达式的运算结果是一个函数。
14.3.1 Lambda表达式标准语法格式
Kotlin中的Lambda表达式很灵活,其标准语法格式如下:
{ 参数列表 ->
Lambda体
}
其中,Lambda表达式的参数列表与函数的参数列表形式类似,但是Lambda表达式参数列表前后没有小括号。箭头符号将参数列表与Lambda体分隔开,Lambda表达式不需要声明返回类型。Lambda表达式可以有返回值,如果没有return语句Lambda体的最后一个表达式就是Lambda表达式的返回值,如果有return语句返回值是return语句后面的表达式。
重构14.2.2节示例代码如下:
//代码文件:chapter14/src/com/a51work6/section3/ch14.3.1.kt
package com.a51work6.section3
private fun calculate(opr: Char): (Int, Int) -> Int {
return when (opr) { '+' -> { a: Int, b: Int ->a + b } ① '-' -> { a: Int, b: Int ->a - b } ② '*' -> { a: Int, b: Int ->a * b } ③ else -> { a: Int, b: Int ->a / b } ④ }
}
fun main(args: Array) {
val f1 = calculate(’+’) ⑤
println(f1(10, 5)) //调用f1变量 ⑥
val f2 = calculate(’-’)
println(f2(10, 5))
val f3 = calculate(’*’)
println(f3(10, 5))
val f4 = calculate(’/’)
println(f4(10, 5))
}
calculate函数是高阶函数,它的返回值是函数类型(Int, Int) ->
Int。代码第①行~第④行分别定义了4个Lambda表达式,它们的函数类型(Int, Int) -> Int与calculate函数要求的返回类型是一致的。
代码第⑤行是调用calculate函数,返回值f1也是一个函数,这就是高阶函数。代码第⑥行是调用f1函数。
另外,calculate函数还有表示称为表达式函数体形式,代码如下:
private fun calculate(opr: Char): (Int, Int) -> Int =when (opr) {
‘+’ -> { a: Int, b: Int -> a +b }
‘-’ -> { a: Int, b: Int -> a -b }
‘*’ -> { a: Int, b: Int -> a *b }
else -> { a: Int, b: Int -> a /b }
}
比较上述代码不难发现,表达式函数体要比代码块函数体代码简洁很多。
14.3.2 使用Lambda表达式
Lambda表达式也是函数类型,可以声明变量,也可以作为其他函数的参数或者返回值使用。14.3.1节示例已经实现了Lambda表达式返回值使用,下面介绍一个Lambda表达式作为参数使用示例,示例代码如下:
//代码文件:chapter14/src/com/a51work6/section3/ch14.3.2.kt
package com.a51work6.section3
//打印计算结果函数
fun calculatePrint(n1: Int,
n2: Int,
opr: Char,
funN: (Int, Int) ->Int) {//函数类型 ①
println("$n1 $opr $n2 = ${funN(n1,n2)}")
}
fun main(args: Array) {
calculatePrint(10, 5, ‘+’, { a: Int,b: Int -> a + b }) ②
calculatePrint(10, 5, ‘-’, funN = {a: Int, b: Int -> a - b }) ③
}
代码第①行calculatePrint函数的最后一个参数是函数类型(Int, Int) -> Int。代码第②行是调用calculatePrint,第三个参数传递是的Lambda表达式。代码第③行是调用calculatePrint,第三个参数采用命名参数方式,传递是的Lambda表达式。
14.3.3 Lambda表达式简化写法
Kotlin提供了多种Lambda表达式简化写法,下面介绍其中几种。
1.参数类型推导简化
类型推导是Kotlin的强项,Kotlin编译器可以根据上下文环境推导出参数类型和返回值类型。以下代码是标准形式的Lambda表达式:
{ a: Int, b: Int -> a + b }
Kotlin能推导出参数a和b是Int类型,当然返回值也是Int类型。简化形式如下:
{ a, b -> a + b }
使用这种简化方式修改后的calculate函数代码如下:
private fun calculate(opr: Char): (Int, Int) -> Int =
when (opr) {
‘+’ -> { a, b -> a + b }
‘-’ -> { a, b -> a - b }
‘*’ -> { a, b -> a * b }
else -> { a, b -> a / b }
}
上述代码的Lambda表达式是14.3.1节示例的简化写法,其中a和b是参数。
2.使用尾随Lambda表达式
Lambda表达式可以作为函数的参数传递,如果Lambda表达式很长,就会影响程序的可读性。如果一个函数的最后一个参数是Lambda表达式,那么这个Lambda表达式可以放在函数括号之后。示例代码如下:
fun calculatePrint1(funN: (Int, Int) -> Int) { //参数是函数类型 ①
//使用funN参数
println("${funN(10, 5)}")
}
//打印计算结果函数
//ch14.3.2.kt中的calculatePrint
fun calculatePrint(n1: Int,
n2: Int,
opr: Char,
funN: (Int, Int) ->Int) {//最后一个参数是函数类型 ②
println("${n1} ${opr} n2={n2} =n2={funN(n1, n2)}")
}
fun main(args: Array) {
calculatePrint(10, 5, '+', { a, b-> a + b })//标准形式 calculatePrint(10, 5, '-') { a, b-> a - b }//尾随Lambda表达式形式 ③ calculatePrint1({ a, b -> a + b})//标准形式 calculatePrint1() { a, b -> a + b}//尾随Lambda表达式形式 ④ calculatePrint1 { a, b -> a + b}//尾随Lambda表达式,如果只有没有参数可省略括号 ⑤
}
上述代码第①行和第②行定义了两个高阶函数,它们的最后一个参数都是函数类型。代码第③行、第④行和第⑤行都是采用尾随Lambda表达式形式调用函数。由于调用calculatePrint1函数采用了尾随Lambda表达式形式,这样一来它的小括号中就没有参数了,这种情况下可以省略小括号,见代码第⑤行。
3.省略参数声明
如果Lambda表达式的参数只有一个,并且能够根据上下文环境推导出它的数据类型,那么这个参数声明可以省略,在Lambda体中使用隐式参数it替代Lambda表达式的参数。示例代码如下:
fun revreseAndPrint(str: String, funN: (String) -> String)
{ ①
val result = funN(str)
println(result)
}
fun main(args: Array) {
revreseAndPrint("hello", {s -> s.reversed() })//标准形式 ② revreseAndPrint("hello", {it.reversed() })//省略参数,使用隐式参数it ③ val result1 = { a: Int ->println(a) }//不能省略参数声明 ④ val result2:(Int)->Unit = {println(it) }//可以省略参数声明 ⑤ result2(30) //输出结果是30
}
上述代码第①行是定义反转并打印字符串高阶函数revreseAndPrint,它的第二个参数是函数类型(String) -> String)。代码第②行和第③行是调用revreseAndPrint函数,区别是代码第②行采用是标准的Lambda表达式,而代码第③行省略了参数s声明,使用it隐式变量替代。
14.3.4 Lambda表达式与return语句
Lambda表达式体中也可以使用return语句,它会使程序跳出Lambda表达式体。示例代码如下:
//代码文件:chapter14/src/com/a51work6/section3/ch14.3.4.kt
package com.a51work6.section3
//累加求和函数
fun sum(vararg num: Int): Int {
var total = 0 num.forEach { ① //if (it ==10) return -1 //返回最近的函数 ② if (it ==10) return@forEach//返回Lambda表达式函数 ③ total += it } return total
}
fun main(args: Array) {
val n = sum(1,2, 10, 3) println(n) //6 val add =label@ { ④ val a = 1 val b = 2
return@label 10 ⑤
a + b
}
//调用Lambda表达式add
println(add()) //10
}
上述代码第①行是使用了forEach函数,它后面的Lambda表达式,如果使用代码第②行if (it == 10) return -1语句,则会返回最近的函数,即sum函数,不是返回Lambda表达式forEach。为了返回Lambda表达式则需要在return语句后面加上标签,见代码第③行,@forEach是隐式声明标签,标签名是Lambda表达式所在函数名(forEach)。也可以为Lambda表达式声明显示标签,代码第④行label@是Lambda表达式显示声明标签,代码第⑤行是使用显示标签。
14.4闭包与捕获变量
闭包(closure)是一种特殊的函数,它可以访问函数体之外的变量,这个变量和函数一同存在,即使已经离开了它的原始作用域也不例外。这种特殊函数一般是局部函数、匿名函数或Lambda表达式。
闭包可以访问函数体之外的变量,这个过程称为捕获变量。示例代码如下:
// 全局变量
var value = 10
fun main(args: Array) {
//局部变量
var localValue = 20
val result = { a: Int -> ① value++ ② localValue++ ③ val c = a + value + localValue ④ println(c) } result(30) //输出结果是62
println("localValue = " + localValue) //输出结果是localValue = 21
println("value= " + value) //输出结果是value = 11
}
本例中的闭包是捕获value和localValue变量的Lambda表达式。代码第①行是Lambda表达式,在Lambda体中捕获变量value和localValue。代码第②行是修改全局变量value,代码第③行是修改局部变量localValue。代码第④行是读取value和localValue变量。
下面是一个局部函数示例:
fun makeArray(): (Int) -> Int { ①
var ary = 0 ② //局部函数捕获变量 fun add(element: Int): Int { ③ ary += element ④ return ary ⑤ } return ::add ⑥
}
fun main(args: Array) {
val f1 = makeArray() ⑦ println("---f1---") println(f1(10))//累加ary变量,输出结果是10 println(f1(20))//累加ary变量,输出结果是30 println(f1(30))//累加ary变量,输出结果是60
}
在上述代码中,第①行定义函数makeArray,它的返回值是(Int) -> Int函数类型。第②行声明并初始化变量ary,它的作用域是makeArray函数体。第③行代码定义了局部函数add,在add函数体内,第④行代码修改变量ary值。第⑤行代码是从add函数中返回变量ary。第⑥行代码是返回局部函数::add引用。
这样当在第⑦行调用的时,f1是局部函数add的一个变量。需要注意的是,f1每次调用时,ary变量作用域已经不存在,但是ary变量值都能够被保持。
上述示例也可以改为匿名函数实现,代码如下所示:
fun makeArray(): (Int) -> Int {
var ary = 0 //匿名函数形式捕获变量 return fun(element: Int): Int { ① ary +=element return ary ② }
}
makeArray函数返回一个匿名函数,见代码第①行。代码第②行是匿名函数返回值。比较匿名函数与局部函数,会发现Lambda表达式代码比较简洁,实现的结果完全一样。
上述示例也可以改为Lambda表达式实现,代码如下所示:
fun makeArray(): (Int) -> Int {
var ary = 0 //Lambda表达式形式捕获变量 return { element -> ① ary += element ary ② }
}
makeArray函数返回一个Lambda表达式,见代码第①行。代码第②行是Lambda表达式返回值,在ary是Lambda体的最后一行,它是Lambda表达式返回值,不需要return语句。比较Lambda表达式与匿名函数和局部函数,会发现Lambda表达式代码最为简洁,最后实现的结果完全一样。
14.5 内联函数
在高阶函数中参数如果是函数类型,则可以接收Lambda表达式,而Lambda表达式在编译时被编译称为一个匿名类,每次调用函数时都会创建一个对象,如果这种被函数反复调用则创建很多对象,会带来运行时额外开销。为了解决次问题,在Kotlin中可以将这种函数声明为内联函数。
14.5.1 自定义内联函数
Kotlin标准库提供了很多常用的内联函数,开发人员可以自定义内联函数,但是如果函数参数不是函数类型,不能接收Lambda表达式,那么这种函数一般不声明为内联函数。声明内联函数需要使用关键字inline修饰。
示例代码如下:
//代码文件:chapter14/src/com/a51work6/section5/ch14.5.1.kt
package com.a51work6.section5
//内联函数
inline fun calculatePrint(funN: (Int, Int) -> Int) { ①
println("${funN(10, 5)}")
}
fun main(args: Array) {
calculatePrint{ a, b -> a + b } ②
calculatePrint{ a, b -> a - b } ③
}
上述代码第①行声明了一个内联函数calculatePrint,它的参数是(Int, Int) -> Int函数类型,它可以接收Lambda表达式。代码第②行和第③行分别调用了calculatePrint函数。
14.5.2 使用let函数
在Kotlin中一个函数参数被声明为非空类型时,也可以接收可空类型的参数,但是如果实际参数如果真的为空,可能会导致比较严重的问题。因此需要在参数传递之前判断可空参数是否为非空,示例代码如下:
//代码文件:chapter14/src/com/a51work6/section5/ch14.5.2.kt
package com.a51work6.section5
fun square(num: Int): Int = num * num ①
fun main(args: Array) {
val n1: Int? = 10 //null ②
//自己进行非空判断
if (n1 != null) { ③
println(square(n1)) ④
}
}
上述代码第①行是声明一个函数square,参数是非空整数类型,该函数实现一个整数的平方运算。代码第②行是声明一个可空整数类型(Int?)变量n1,代码第③行是判断n1是否为非空,如果非空才调用,见代码第④行。
自己判断一个对象非空比较麻烦。在Kotlin中任何对象都可以一个let函数,let函数后面尾随一个Lambda表达式,在对象非空时执行Lambda表达式中的代码,为空时则不执行。
示例代码如下:
n1?.let { n -> println(square(n)) }
n1?.let { println(square(it)) }
这两行代码都是使用let函数进行调用效果是一样的,当n1非空时执行Lambda表达式中的代码,如果n1为空则不执行。n1?.let { println(square(it))
}语句是省略了参数声明,使用隐式参数it替代参数n。
14.5.3 使用with和apply函数
有时候需要对一个对象设置多个属性,或调用多个函数时,可以使用with或apply函数。与let函数类似Kotlin中所有对象都可以使用这两个函数。
示例代码如下:
//代码文件:chapter14/src/com/a51work6/section5/ch14.5.3.kt
package com.a51work6.section5
import java.awt.BorderLayout
import javax.swing.JButton
import javax.swing.JFrame
import javax.swing.JLabel
class MyFrame(title: String) : JFrame(title) {
init { // 创建标签 val label =JLabel("Label") // 创建Button1 val button1= JButton() ①
button1.text = “Button1”
button1.toolTipText = “Button1”
// 注册事件监听器,监听Button1单击事件
button1.addActionListener { label.text = “单击Button1” } ②
// 创建Button2 val button2= JButton().apply { ③ text ="Button2"
toolTipText = “Button2”
// 注册事件监听器,监听Button2单击事件
addActionListener { label.text = “单击Button2” }
// 添加Button2到内容面板
contentPane.add(this, BorderLayout.SOUTH)
} ④
with(contentPane) { ⑤
// 添加标签到内容面板
add(label, BorderLayout.NORTH)
// 添加Button1到内容面板
add(button1, BorderLayout.CENTER)
println(height)
println(this.width)
} ⑥
// 设置窗口大小
setSize(350, 120)
// 设置窗口可见
isVisible =true
}
}
fun main(args: Array) {
//创建Frame对象
MyFrame(“MyFrame”)
}
上述代码是Swing的窗口,Swing是Java的用户图形界面介绍,Swing会在第22章介绍,本示例有图形界面组件的技术细节本暂不讨论。代码第①行和第③行分别创建两按钮对象,其中代码第①行第②行是创建并调用Button1的属性和函数,这传统的做法,由于多次调用同一个对象的属性或函数,可以使用with或apply函数,代码第③行第④行是创建并调用Button2的属性和函数,其中使用apply函数,apply函数后面尾随一个Lambda表达式,需要调用的属性和函数被放到Lambda表达式中,Lambda表达式中省略的对象名button2,例如text = "Button2"表达式说明调用的button2的text属性,apply函数中如果引用当前对象可以使用this关键字,例如contentPane.add(this,
BorderLayout.SOUTH)中的this,apply函数是有返回值的,它的返回值就是当前对象。
如果不需要返回值可以使用with函数,with函数与apply函数类似,代码第⑤行~第⑥行是使用with函数,with函数后面也尾随一个Lambda表达式,需要调用的属性和函数被放到Lambda表达式中,with函数中如果引用当前对象也是使用this关键字。
本章小结
本章主要介绍了高阶函数和Lambda表达式,读者需要理解函数式编程特点。熟悉高阶函数和Lambda表达式特点。掌握Lambda表达式标准语法,了解Lambda表达式的几个简写方式,以及尾随Lambda表达式,熟悉闭包等内容。了解什么是内联函数,以及自定义内联函数,熟悉使用let、with和apply等内联函数的使用场景。
- Python-14-高级特性-函数式编程、lambda表达式、高阶函数、map、reduce、filter、排序、返回函数、闭包closure、装饰器Decrator、偏函数
- Java8新特性Lambda表达式----函数式编程
- 畅游Python 六:基础函数 - 函数式编程和面向过程编程的区别、open函数、lambda表达式、内置参数列表、递归
- 函数式编程之 Lambda 表达式的引出_Java8 实践
- Java8 Lambda表达式 函数式编程
- C# 函数式编程 —— 使用 Lambda 表达式编写递归函数
- 函数式编程之 Lambda 表达式
- Java 函数式编程和 lambda 表达式
- Java 进阶,学习笔记-12 函数式编程以及 Lambda 表达式
- Java函数式编程之最细致的lambda表达式讲解
- java1.8 lambda表达式 函数式编程 闭包
- 【怎样写代码】函数式编程 -- Lambda表达式(二):C#常用委托
- python笔记11 - lambda函数,globals()/locals()函数,eval()exec()函数,闭包函数,函数式编程,高阶函数
- 函数式编程--lambda表达式对比匿名内部类
- Java 函数式编程和 lambda 表达式
- Java 函数式编程 &Lambda表达式
- 函数式编程--lambda表达式对比匿名内部类
- Java8 Lambda表达式 函数式编程 方法引用
- java8实战读书笔记:Lambda表达式语法与函数式编程接口
- java函数式编程之lambda表达式