scala 闭包和柯里化

一、闭包:函数式编程的标配

从 Java 问题引申闭包

在 Java 中,匿名函数不能访问外部变量

public static void main(String[] args) {
    int i = 10;
    Thread t1 = new Thread() {
        @Override
        public void run() {
            System.out.println(i);
        }
    };
    t1.start();
}

此时编译器没有报错,运行也能出结果,但是这个结果很明显不符合要求

但是为什么没有报错呢,此时我们在为 i 重新赋值,发现 原来内部类能引用外部变量是因为java自动将外部变量 i 变成了 final 修饰的属性了
在这里插入图片描述
为什么 内部类访问 外部变量 需要将外部变量声明为 final 呢?就是因为 内部类对象的生命周期会超过局部变量的生命周期, 例如上述例子, 子线程 Thread 正在运行时,main 线程可能已经结束了, main 线程结束了,i 自然而然就被销毁了,但是此时 子线程却还用着 i,就是因为内部类的生命周期大于外部变量的生命周期了

对于上述问题, scala 是如何解决的呢? 答案就是 闭包了;

定义: 闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
通常来说:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和它所处的环境,成为闭包

我们看一段 scala 代码

def main(args: Array[String]): Unit = {
    var a = 10

    def foo(): Unit = {
        println(a)
    }

    foo
}

运行结果为: 10

为什么 foo() 方法能访问到 外部变量 呢? 就是因为 scala 的闭包(foo 函数和变量a组成了闭包),因为闭包的存在,在 mian 函数销毁时,会阻止 变量 i 的销毁

通常来说:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和它所处的环境,成为闭包

下面我们用闭包实现: 任意一个数 n + 4

def main(args: Array[String]): Unit = {
     val a4 = add(4)
     println(a4(5))
     println(a4(6))
     println(a4(7))
 }

 // 这个 add 是一个高阶函数
 // 能接受一个函数 或 返回 一个函数 的函数, 称为高阶函数
 def add(a: Int) = {
     // 匿名函数
     (b: Int) => a + b
 }

运行结果:

9
10
11

上面的写法还是很繁琐,需要调用函数后,返回一个值,由这个值再去调用其中的匿名函数,所以再简化简化

def main(args: Array[String]): Unit = {
//        val a4 = add(4)
//        println(a4(5))
//        println(a4(6))
//        println(a4(7))
    
    println(add(4)(5))
    println(add(4)(6))
    println(add(5)(6))
}

def add(a: Int)(b: Int): Int = a + b

//    def add(a: Int): Int => Int = {
//        // 匿名函数
//        (b: Int) => a + b
//    }

那么 add(4)(5) 和 原来的 add(4, 5) 有什么区别呢?

def main(args: Array[String]): Unit = {
//        val a4 = add(4)
//        println(a4(5))
//        println(a4(6))
//        println(a4(7))

    println(add(4)(5))
    println(add(4)(6))
    println(add(5)(6))
    
    println(add1(4, 5))
}

def add1(a: Int, b: Int): Int = a + b
def add(a: Int)(b: Int): Int = a + b

def add1(a: Int, b: Int): Int = a + b
def add(a: Int)(b: Int): Int = a + b
这两个方法最大的区别在于 闭包,函数 addb 来自于外部变量,而 函数 add1b 来自于传入的参数

我们整个推导过程,成为函数的 柯里化

整个推导过程为:
从原始的

def add1(a: Int, b: Int): Int = a + b

推导出

def add(a: Int) = {
    // 匿名函数
    (b: Int) => a + b
}

推导出

def add(a: Int)(b: Int): Int = a + b

二、柯里化

定义: 把一个参数列表的多个参数,编程多个参数列表

柯里化的底层一定由闭包支撑着

柯里化的用处在 隐式转换、在 spark 中有大量的使用
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值