聊聊闭包(Closures)


          /\
         /**\
        /****\   /\
       /      \ /**\
      /  /\    /    \                
     /  /  \  /      \                             --- __@
    /  /    \/ /\     \                         ---- _`\<,_            KEEP LOOKING  
   /  /      \/  \/\   \                      ----- (*)/ (*)  	               DON`T SETTLE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

一、闭包概念:

闭包即一个函数对象,即使函数对象的调用在它原始作用域之外, 依然能够访问在它词法作用域内的变量。[🐶有点拗口🐶]

闭包的特点:可以捕获和储存上下文的常量或者变量的引用,即使这些常量或者变量在原作用域已经被销毁了,但在代码中仍然可以使用。事实上全局函数和嵌套函数也是一种闭包,对于全局函数它不会捕获任何常量或者变量,而对于嵌套函数则可以捕获其所在函数的常量或者变量。通常我们说的闭包更多指的是闭包表达式,也就是没有函数名称的代码块,因此也叫做匿名闭包。

简单理解就是:闭包保存了一段为匿名函数的代码块,需要的时候再调用。


二、几种语言闭包的简单使用:

1. C语言函数指针

// 加法
int addCallback(int a, int b) {
    return a+b;
}
// 减法
int subtractCallback(int a, int b) {
    return a-b;
}
// 乘法
int multiplyCallback(int a, int b) {
    return a*b;
}
// 除法
int divideCallback(int a, int b) {
    return a/b;
}

/// 计算方法
/// @param a
/// @param b
/// @param callback 为函数指针
int calculate(int a, int b, int (*callback)(int,int)) {
    // 可以做些耗时操作...
    return callback(a,b);// 函数指针的调用,执行具体的函数
}

int main()
{
   int num1 = calculate(1,2, addCallback);// 3
   int num2 = calculate(2, 1, subtractCallback);// 1
   int num3 = calculate(2, 3, multiplyCallback);// 6
   int num4 = calculate(6, 3, divideCallback);// 2
}


2.C++闭包

int addFunc(int a, int b){
    return [](int x, int y){
        return x+y;
    }(a, b);// 自执行匿名函数
}
std::cout << addFunc(1,2) << std::endl;// 输出 3

👀 👆 是不柿这些个语言对闭包的写法都差不多,即: ( 形参 ){ 方法体 }( 调用 )


3.Objective-C闭包【即Block】

int addFunc(int a, int b){// 相当于执行了函数内部的匿名子函数
    return ^(int x,int y){
        return x+y;
    }(a,b);// 自执行Block
}
int num = addFunc(1, 2);
NSLog(@“%d”,num); // 输出 3


// blcok封装了一段代两个数之和的代码块,相当于一个子函数`addNum`
^(int x,int y){
   return x+y;
};
// 子函数
int addNum(int x, int y){
    return x+y;
}

再来看看函数式写法

@interface AddBlock : NSObject
- (int (^)(int a,int b))add;
@end

@implementation AddBlock
- (int (^)(int,int))add{
    return  ^(int a, int b){
        return a+b;
    };
}
@end


// some code...
AddBlock *block = [[AddBlock alloc] init];
block.add(1,2);// 函数式写法

4.JavaScript闭包 【函数作为一等公民】

//返回值为一个匿名函数
function addFunc1() {
    return function(a ,b) {
        let c = a+b // 通过闭包使得外部可以间接访问内部匿名函数作用域中的变量`c`
        return c;
    }
}
var add = addFunc1()// add变量封装了一段执行两个数之和的代码块,即add是执行两数之和的匿名函数
console.log(add(1,2))// 需要时载执行加法运算

// 将匿名自执行子函数封装在外部函数内
function addFunc2(x, y) {
    return function(a, b){
        return a+b
    }(x, y)// 匿名自执行函数
}
// 外部函数调用了内部匿名自执行函数,间接访问了变量【即a+b的结果】
console.log(addFunc2(1,2)) // 输出 3


// Lambda写法,同addFunc2
function addFunc3(x, y) {
    return ((a, b) => a + b)(x, y);
}
console.log(addFunc3(1,2))


5.Dart闭包 【函数作为一等公民】

//返回值为一个匿名函数
Function addFunc1() {
    return (int a, int b) {
        var c = a+b; // 通过闭包使得外部可以间接访问内部匿名函数作用域中的变量`c`
        return c;
    };
}
var add = addFunc1();// add变量封装了一段执行两个数之和的代码块,即add是执行两数之和的匿名函数
var num = add(1,2);// 需要时载执行加法运算
print("${num.toString()}”);// 输出 3

// 将匿名自执行子函数封装在外部函数内
int addFunc2(int x, int y) {
    return (int a, int b) {
        return a+b;
    }(x, y);// 匿名自执行函数
}
// 外部函数调用了内部匿名自执行函数,间接访问了变量【即a+b的结果】
print("${addFunc2(1, 2).toString()}”);// 输出 3

// Lambda表达式写法,同addFunc2
int addFunc3(int x, int y) {
    return ((a, b) => a + b)(x, y);
}
print("${addFunc1(1, 2).toString()}”);// 输出 3


6.Swift闭包【函数作为一等公民】

通过闭包表达式定义函数

let add = {(a: Int, b: Int) -> Int in 
   return a+b 
}
let num = add(1, 2)
print (num) // 输出 3

闭包表达式作为参数

func calculate(v1: Int, v2: Int, fn:(Int, Int) -> Int, v3: Int) -> Int {
    fn(v1,v2) + v3
}

calculate(v1: 1, v2: 2, fn: {
    (v1: Int, v2: Int) -> Int in
    return v1 + v2
},v3: 3)

// 简写方式1
calculate(v1: 1, v2: 2, fn: {
    v1, v2 -> Int in
    return v1 + v2
},v3: 3)

// 简写方式2
calculate(v1: 1, v2: 2, fn: {
    v1, v2 -> Int in v1 + v2
},v3: 3)


// 简写方式3
calculate(v1: 1, v2: 2, fn: {
    $0 + $1
},v3: 3)

// 简写方式4 , 编译器会自动识别 + 为加法运算符,并将v1和v2相加
calculate(v1: 1, v2: 2, fn: +, v3: 3)


尾随闭包写法

func calculate(v1: Int, v2: Int, fn:(Int, Int) -> Int) -> Int {
   return fn(v1,v2)
}

// 尾随闭包写法
calculate(v1: 1, v2: 2) {
    (v1: Int, v2: Int) -> Int in
    return v1+v2
}

calculate(v1: 1, v2: 2) {
    v1, v2 -> Int in v1+v2
}

calculate(v1: 1, v2: 2) {
    $0 + $1
}



三、闭包能干嘛?(来自灵魂的拷问)

  • 闭包的价值在于可以作为函数对象或者匿名函数,持有上下文数据,作为第一级对象进行传递和保存。
  • 闭包广泛用于回调函数、函数式编程中。

以上

----------End------------

posted @ 2022-12-30 10:14  ITRyan  阅读(38)  评论(0编辑  收藏  举报