美文网首页
Kotlin函数式编程 (3)✔️闭包与捕获变量

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

作者: 狼性代码人 | 来源:发表于2019-06-06 08:33 被阅读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 变量值都能够被保持,由此说明被捕获的变量都存储在一个特殊的容器内,而这个变量和函数一同存在。

    相关文章

      网友评论

          本文标题:Kotlin函数式编程 (3)✔️闭包与捕获变量

          本文链接:https://www.haomeiwen.com/subject/citsxctx.html