聊聊闭包(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------------
(限于水平,本文可能存在瑕疵甚至错误的地方。如有发现,还请留言指正,相互学习。thx! )
KEEP LOOKING, DON`T SETTLE!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理