回调函数,光听名字就比普通函数要高大上一些,那到底什么是回调函数呢?恕我读得书少,没有在那本书上看到关于回调函数的定义。我在百度上搜了一下,发现众说纷纭,有很大一部分都是使用相似这么一个场景来讲明:A君去B君店里买东西,刚好缺货,A君留下号码给B君,有货时通知A君。感受这个让人更容易想到的是异步操做,而不是回调。另外还有两句英文让我印象深入:1) If you call me, I will call you back; 2) Don't call me, I will call you. 看起来好像颇有道理,可是仔细一想,普通函数不也能够作到这两点吗?因此,我以为这样的说法都不是很稳当,由于我以为这些说法都没有把回调函数的特色表达出来,也就是都看不到和普通函数到底有什么差异。不过,百度百科的解析我以为还算不错(虽然常常吐槽百度搜索...):回调函数就是一个经过函数指针调用的函数。若是你把函数的指针(地址)做为参数传递给另外一个函数,当这个指针被用来调用其所指向的函数时,咱们就说这是回调函数。app
下面先说说个人见解。咱们能够先在字面上先作个分解,对于“回调函数”,中文其实能够理解为这么两种意思:1) 被回调的函数;2) 回头执行调用动做的函数。那这个回头调用又是什么鬼?异步
先来看看来自维基百科的对回调(Callback)的解析:In computer programming, a callback is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time. This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback. 也就是说,把一段可执行的代码像参数传递那样传给其余代码,而这段代码会在某个时刻被调用执行,这就叫作回调。若是代码当即被执行就称为同步回调,若是在以后晚点的某个时间再执行,则称之为异步回调。关于同步和异步,这里不做讨论,请查阅相关资料。async
再来看看来自Stack Overflow某位大神简洁明了的表述:A "callback" is any function that is called by another function which takes the first function as a parameter。 也就是说,函数 F1 调用函数 F2 的时候,函数 F1 经过参数给 函数 F2 传递了另一个函数 F3 的指针,在函数 F2 执行的过程当中,函数F2 调用了函数 F3,这个动做就叫作回调(Callback),而先被当作指针传入、后面又被回调的函数 F3 就是回调函数。到此应该明白回调函数的定义了吧?函数
不少朋友可能会想,为何不像普通函数调用那样,在回调的地方直接写函数的名字呢?这样不也能够吗?为何非得用回调函数呢?有这个想法很好,由于在网上看到解析回调函数的不少例子,其实彻底能够用普通函数调用来实现的。要回答这个问题,咱们先来了解一下回到函数的好处和做用,那就是解耦,对,就是这么简单的答案,就是由于这个特色,普通函数代替不了回调函数。因此,在我眼里,这才是回调函数最大的特色。来看看维基百科上面我以为画得很好的一张图片。this
Callbackspa
下面以一段不完整的C语言代码来呈现上图的意思:指针
#include<stdio.h> #include<softwareLib.h> // 包含Library Function所在读得Software library库的头文件 int Callback() // Callback Function { // TODO return 0; } int main() // Main program { // TODO Library(Callback); // TODO return 0; }
乍一看,回调彷佛只是函数间的调用,和普通函数调用没啥区别,但仔细一看,能够发现二者之间的一个关键的不一样:在回调中,主程序把回调函数像参数同样传入库函数。这样一来,只要咱们改变传进库函数的参数,就能够实现不一样的功能,这样有没有以为很灵活?而且丝绝不须要修改库函数的实现,这就是解耦。再仔细看看,主函数和回调函数是在同一层的,而库函数在另一层,想想,若是库函数对咱们不可见,咱们修改不了库函数的实现,也就是说不能经过修改库函数让库函数调用普通函数那样实现,那咱们就只能经过传入不一样的回调函数了,这也就是在平常工做中常见的状况。如今再把main()、Library()和Callback()函数套回前面 F一、F2和F3函数里面,是否是就更明白了?code
明白了回调函数的特色,是否是也能够大概知道它应该在什么状况下使用了?没错,你能够在不少地方使用回调函数来代替普通的函数调用,可是在我看来,若是须要下降耦合度的时候,更应该使用回调函数。blog
知道了什么是回调函数,了解了回调函数的特色,那么应该怎么使用回调函数?下面来看一段简单的能够执行的同步回调函数代码。图片
#include<stdio.h> int Callback_1() // Callback Function 1 { printf("Hello, this is Callback_1 "); return 0; } int Callback_2() // Callback Function 2 { printf("Hello, this is Callback_2 "); return 0; } int Callback_3() // Callback Function 3 { printf("Hello, this is Callback_3 "); return 0; } int Handle(int (*Callback)()) { printf("Entering Handle Function. "); Callback(); printf("Leaving Handle Function. "); } int main() { printf("Entering Main Function. "); Handle(Callback_1); Handle(Callback_2); Handle(Callback_3); printf("Leaving Main Function. "); return 0; } 运行结果: Entering Main Function. Entering Handle Function. Hello, this is Callback_1 Leaving Handle Function. Entering Handle Function. Hello, this is Callback_2 Leaving Handle Function. Entering Handle Function. Hello, this is Callback_3 Leaving Handle Function. Leaving Main Function.
能够看到,Handle()函数里面的参数是一个指针,在main()函数里调用Handle()函数的时候,给它传入了函数Callback_1()/Callback_2()/Callback_3()的函数名,这时候的函数名就是对应函数的指针,也就是说,回调函数其实就是函数指针的一种用法。如今再读一遍这句话:A "callback" is any function that is called by another function which takes the first function as a parameter,是否是就更明白了呢?
眼尖的朋友可能发现了,前面的例子里面回调函数是没有参数的,那么咱们能不能回调那些带参数的函数呢?答案是确定的。那么怎么调用呢?咱们稍微修改一下上面的例子就能够了:
#include<stdio.h> int Callback_1(int x) // Callback Function 1 { printf("Hello, this is Callback_1: x = %d ", x); return 0; } int Callback_2(int x) // Callback Function 2 { printf("Hello, this is Callback_2: x = %d ", x); return 0; } int Callback_3(int x) // Callback Function 3 { printf("Hello, this is Callback_3: x = %d ", x); return 0; } int Handle(int y, int (*Callback)(int)) { printf("Entering Handle Function. "); Callback(y); printf("Leaving Handle Function. "); } int main() { int a = 2; int b = 4; int c = 6; printf("Entering Main Function. "); Handle(a, Callback_1); Handle(b, Callback_2); Handle(c, Callback_3); printf("Leaving Main Function. "); return 0; } 运行结果: Entering Main Function. Entering Handle Function. Hello, this is Callback_1: x = 2 Leaving Handle Function. Entering Handle Function. Hello, this is Callback_2: x = 4 Leaving Handle Function. Entering Handle Function. Hello, this is Callback_3: x = 6 Leaving Handle Function. Leaving Main Function.
能够看到,并非直接把int Handle(int (*Callback)()) 改为 int Handle(int (*Callback)(int)) 就能够的,而是经过另外增长一个参数来保存回调函数的参数值,像这里 int Handle(int y, int (*Callback)(int)) 的参数 y。同理,可使用多个参数的回调函数。