闭包基础 | 青训营笔记

107 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的第6天

闭包基础

闭包本身是一个结构体,存储了函数入口地址和与之绑定的一系列环境,环境里面既有其本身内部定义的变量(约束变量),又包含从外部捕获的变量(自由变量),捕获变量的处理因实现而异。

闭包在各个语言中的表现形式

  • C++

    C++中闭包的表现形式就是lambda表达式,C++11中正式添加了对其的支持

    #include <algorithm>
    #include <cmath>
    
    void abssort(float* x, unsigned n) {
        std::sort(x, x + n,
            // Lambda expression begins
            [](float a, float b) {
                return (std::abs(a) < std::abs(b));
            } // end of lambda expression
        );
    }
    
  • Python

    python中,闭包以内部函数的形式存在

    def make_multiplier_of(n):
      def multiplier(x):
        return x * n;
      return multiplier;
    
  • Objective-C

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
      @autoreleasepool {
        int i = 1024;
        void (^printBlock)(void) = ^{
          printf("%d\n", i);
        };
        printBlock();
      }
      return 0;
    }
    

Block 基础

  • block 是闭包在 Objective-C 中的实现
  • block 可以接受参数也可以有返回值
  • block 可以分配在栈和堆上,也可以是全局的。分配到栈上的块可以拷贝到堆中,同标准的 Objective-C 对象一样,具备引用计数

1. 标准格式

// block声明
returnType (^blockName)(parameters);
// block赋值
^returnType(parameters) {
  // do something;
};
// 示例
int (^sumBlock)(int a, int b) = ^int(int a, int b) {
  return a + b;
};
int sum = sumBlock(1, 1);

block 在声明时有几个组成部分,返回值,block 的名称以及 block 传入的参数;而在给 block 赋值时,没有 block 名称这一部分,在对应的位置用返回值代替

2. 常用简写

  • 省略写法

    // 有返回值有入参
    int (^sumBlock)(int, int) = ^(int a, int b) {
        return a + b;
    };
    // 无返回值无入参
    void (^printBlock)(void) = ^{
        NSLog(@"Hello World!");
    };
    

    对于 block 的声明来说,唯一可以省略的就是非空入参的变量名,而 block 的赋值无论是否有返回值,都可以将其省略,编译器会自动根据左侧声明检查对应的返回值是否满足要求,当函数没有入参时,还可以进一步简化为^{}的形式

  • typedef

    typedef returnType (^blockName)(parameters);
    
    typedef int (^SumBlock)(int a, int b);
    SumBlock block = ^(int a, int b) {
        return a + b;
    };
    

    面对过于冗长的声明,我们可以通过给常用 block 声明定义别名的形式来简化,只需要在 block 声明的左边加上关键字 typedef 即可。需要注意的是,由于我们这里相当于声明了一种类型,所以 blockNametypedef 时的命名一般与类的命名相同,首字母大写