Kotlin函数式编程 (3)✔️闭包与捕获变量

2019-06-06  本文已影响0人  狼性代码人
  • 闭包定义
  • Java 与 Koltin 中 Lambda 捕获局部变量区别
  • 闭包捕获的变量可以脱离原始作用域而存在

一、闭包定义

  闭包 是一种特殊的函数,它可以访问函数体之外的变量,这个变量和函数一同存在,即使已经离开了它的原始作用域也不例外。这种特殊函数一般是局部函数、匿名函数或 Lambda 表达式。

  闭包可以访问函数体之外的变量,这个过程称为捕获变量。

// 全局变量
var value = 0

fun main(args: Array<String>?) {
    // 局部变量
    var localValue = 20

    val result = { a: Int ->
        value++
        localValue++
        val c = a + value + localValue
        println(c)
    }

    result(30)

    println("value = $value")
    println("localValue = $localValue")
}

2019-06-05 16:53:27.124 28646-28646/cn.ak.kot I/System.out: 52
2019-06-05 16:53:27.124 28646-28646/cn.ak.kot I/System.out: value = 1
2019-06-05 16:53:27.125 28646-28646/cn.ak.kot I/System.out: localValue = 21

  上述代码中 闭包是捕获 valuelocalValue 变量的 Lambda 表达式。

二、Java 与 Koltin 中 Lambda 捕获局部变量区别

  Java 中 Lambda 表达式捕获局部变量时,局部变量只能是 final 的。在 Lambda 体中只能读取局部变量,不能修改局部变量。而 kotlin 中没有这个限制,可以读取和修改局部变量。如下面代码:

// 声明了一个Java代码接口
@FunctionalInterface
public interface Clickable {
    void onClick();
}
// Java中的Lambda表达式局部变量捕获
public class Closure {

    private void closure(Clickable clickable) {
        clickable.onClick();
    }

    public void main(ArrayList<String> args) {
        int count = 0;
        closure(() -> {
            count += 1; // 1️⃣编译错误,count需要使用final修饰
        });
        System.out.println(count);
    }
}

  Java中代码第1️⃣行是编译不过的,必须设置为 countfinal 才能通过编译,但又不能对 count 进行修改,如果非要修改 count 只能把 count 声明为 Closure 的成员变量。

  对比 Kotlin 代码实现:

class Closure {

    private fun closure(clickable: Clickable) {
        clickable.onClick()
    }

    fun main(args: Array<String>) {
        var count: Int = 0
        closure(Clickable { count += 1 }) // 编译正常
        println(count)  // 2
    }
}

三、闭包捕获的变量可以脱离原始作用域而存在

  闭包捕获变量后,这些变量被保存在一个特殊的容器中村存储起来。即便是声明这些变量的原始作用域已经不存在,闭包中仍然可以访问这些变量。

fun sum(): (Int) -> Int { // 2️⃣
    var total = 0 // 3️⃣

    return { // 4️⃣
        total += it
        total
    }
}

fun main(args: Array<String>?) {
    val f1 = sum()  // 5️⃣
    println(f1(10))
    println(f1(10))
    println(f1(10))
    println(f1(10))
}

2019-06-05 17:20:55.912 30314-30314/cn.ak.kot I/System.out: 10
2019-06-05 17:20:55.912 30314-30314/cn.ak.kot I/System.out: 20
2019-06-05 17:20:55.912 30314-30314/cn.ak.kot I/System.out: 30
2019-06-05 17:20:55.913 30314-30314/cn.ak.kot I/System.out: 40

  代码第1️⃣行声明高阶函数sum()返回值类型为(Int) -> Int函数类型;第3️⃣行定义了一个total局部变量,作用域为sum()高阶函数内;第4️⃣行使用 Lambda 表达式作为 高阶函数sum()返回值。
  代码第5️⃣行声明变量 f1,注意 f1 类型是(Int) -> IntLambda表达式。连续执行 4次f1(10)后打印结果为10、20、30、40的累加结果,f1 又是Lambda表达式引用,而Lambda表达式的返回值是局部变量total,但是total的作用域是在高阶函数sum()中,每次 f1 执行完时,total变量的作用域就不存在了,可是 total 变量值都能够被保持,由此说明被捕获的变量都存储在一个特殊的容器内,而这个变量和函数一同存在。

上一篇下一篇

猜你喜欢

热点阅读