今天开始学习Kotlin的第二大思想,函数式编程。
函数式编程在中一切都是函数。
核心概念:
- 函数和其它数据类型是一样的,可以作为其它函数的参数传入,也可做为函数的返回值。
- 使用表达式,不用语句。
- 高阶函数:一个函数可做为另一个函数的参数和返回值
- 无副作用:函数执行过程会返回一个结果,不会修改外部变量
高阶函数
函数式编程的关键是支持高阶函数,就是说一个函数可以做为另一个函数参数或者返回值。
函数类型
先看一下什么是函数类型,在Kotlin中每个函数都有一个类型,称为函数类型,函数类型是中数据类型
fun main(args: Array<String>) {
var a: (Int, Int) -> Int = ::add
println(a(1, 2))
}
fun add(a: Int, b: Int): Int {
return a + b
}
第三行中的 (Int, Int) -> Int 就是函数类型,意思声明一个属性类型为函数类型。
(Int, Int) 说明这个函数要满足,两个Int参数 -> Int 是指返回值是Int类型。
(参数:参数类型)->返回值类型 参数可以有多个,也可以没有就省略。
fun main(args: Array<String>) {
var a: () -> Unit = ::test
println(a())
}
fun test() {
println("无返回值的函数")
}
这是无返回值的函数,如果,不学返回值默认为无返回值。
函数字面量
函数类型可以声明的变量就是函数字面量
函数字面量可以接收三种类型的数据类型。
- 函数的引用
- 匿名函数
- Lambda表达式
fun main(args: Array<String>) {
var a = ::add //函数的引用
var b = ::sub //函数的引用
println(a(1, 1))
println(b(2, 1))
println(ride(1, 10)) //匿名函数
println(divide(10, 1)) //Lambda表达式
}
fun add(a: Int, b: Int): Int {
return a + b
}
fun sub(a: Int, b: Int): Int {
return a - b
}
var ride = fun(a: Int, b: Int): Int {
return a * b
}
var divide = { a: Int, b: Int -> a / b }
函数返回值
把一个函数做另一个函数的返回值使用,这个函数就是高阶函数。
fun main(args: Array<String>) {
val getfun = getfun("add")
println(getfun(1, 2))
}
fun getfun(string: String): (Int, Int) -> Int {
var a: (Int, Int) -> Int
when (string) {
"add" -> a = ::add
else -> {
a = ::sum
}
}
return a
}
fun add(a: Int, b: Int): Int {
return a + b
}
fun sum(a: Int, b: Int): Int {
return a + b
}
函数参数
fun main(args: Array<String>) {
setFun(add(1, 2))
}
fun setFun(funName: (Int, Int) -> Int) {
println(funName)
}
fun add(a: Int, b: Int): (Int, Int) -> Int {
return fun(a: Int, b: Int): Int {
return a + b
}
}
Lambda表达式
Lambda表达式是一种匿名函数,它可以做表达式、函数、参数和返回值用
刚才的案例可以改为Lambda表达式用
fun main(args: Array<String>) {
setFun({ a, b -> a + b })
}
fun setFun(funName: (Int, Int) -> Int) {
println(funName)
}
fun add(a: Int, b: Int): (Int, Int) -> Int {
return { a, b -> a + b }
}
Lambda 怎么写
{参数列表:参数类型->Lambda体}
或者在简写{参数列表->Lambda体}
不写参数类型,因为有时候可以自动推到类型Lambda
尾随Lambda
fun main(args: Array<String>) {
setFun() { a, b -> a + b }
}
fun setFun(funName: (Int, Int) -> Int) {
println(funName(1, 2))
}
如果函数最后一个是Lambda的时候就可以放到小括号外面
省略参数声明
fun main(args: Array<String>) {
getString("abc", { it.reversed() })
}
fun getString(s: String, funName: (String) -> String) {
println(funName(s))
}
Lambda中的return语句
在Lambda直接使用return会使函数直接退出,而不是退出Lambda表达式。
fun main(args: Array<String>) {
getString("aaAbbb")
}
fun getString(s: String) {
s.forEach {
println(it)
if (it == 'A') {
return
}
println("Lambda")
}
println("函数退出")
}
没有打印出 函数退出,证明它直接结束了函数,而非Lambda表达式。
我们用之前学的知识改一下
fun main(args: Array<String>) {
getString("aaAbbb")
}
fun getString(s: String) {
forEach@ s.forEach {
println(it)
if (it == 'A') {
return@forEach
}
println("Lambda")
}
println("函数退出")
}
结果:
这次看到了,说明是结束的Lambda表达式
闭包与捕获变量
闭包使一种特殊的函数,它可以访问函数体之外的变量
fun main(args: Array<String>) {
val test = test()
println(test(10))
println(test(10))
println(test(10))
}
fun test(): (Int) -> Int {
var vaule = 10
fun add(a: Int): Int {
vaule += a
return vaule
}
return ::add
}
结果:
可以看到,结果是累加了,这就是闭包捕获变量。这些变量会被保存到一个特殊的容器中,即使超过作用域在闭包体中也可以访问到。
内联函数
待补充