回調函數,光聽名字就比普通函數要高大上一些,那到底什麼是回調函數呢?恕我讀得書少,沒有在那本書上看到關於回調函數的定義。我在百度上搜了一下,發現衆說紛紜,有很大一部分都是使用相似這麼一個場景來講明: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>code
#include<softwareLib.h> // 包含Library Function所在讀得Software library庫的頭文件blog
int Callback() // Callback Function圖片
{
// TODO
return 0;
}
int main() // Main program
{
// TODO
Library(Callback);
// TODO
return 0;
}
乍一看,回調彷佛只是函數間的調用,和普通函數調用沒啥區別,但仔細一看,能夠發現二者之間的一個關鍵的不一樣:在回調中,主程序把回調函數像參數同樣傳入庫函數。這樣一來,只要咱們改變傳進庫函數的參數,就能夠實現不一樣的功能,這樣有沒有以爲很靈活?而且絲絕不須要修改庫函數的實現,這就是解耦。再仔細看看,主函數和回調函數是在同一層的,而庫函數在另一層,想想,若是庫函數對咱們不可見,咱們修改不了庫函數的實現,也就是說不能經過修改庫函數讓庫函數調用普通函數那樣實現,那咱們就只能經過傳入不一樣的回調函數了,這也就是在平常工做中常見的狀況。如今再把main()、Library()和Callback()函數套回前面 F一、F2和F3函數裏面,是否是就更明白了?
明白了回調函數的特色,是否是也能夠大概知道它應該在什麼狀況下使用了?沒錯,你能夠在不少地方使用回調函數來代替普通的函數調用,可是在我看來,若是須要下降耦合度的時候,更應該使用回調函數。
知道了什麼是回調函數,瞭解了回調函數的特色,那麼應該怎麼使用回調函數?下面來看一段簡單的能夠執行的同步回調函數代碼。
#include<stdio.h>
int Callback_1() // Callback Function 1
{
printf("Hello, this is Callback_1\n");
return 0;
}
int Callback_2() // Callback Function 2
{
printf("Hello, this is Callback_2\n");
return 0;
}
int Callback_3() // Callback Function 3
{
printf("Hello, this is Callback_3\n");
return 0;
}
int Handle(int (*Callback)())
{
printf("Entering Handle Function.\n");
Callback();
printf("Leaving Handle Function.\n");
}
int main()
{
printf("Entering Main Function.\n");
Handle(Callback_1);
Handle(Callback_2);
Handle(Callback_3);
printf("Leaving Main Function.\n");
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\n", x);
return 0;
}
int Callback_2(int x) // Callback Function 2
{
printf("Hello, this is Callback_2: x = %d\n", x);
return 0;
}
int Callback_3(int x) // Callback Function 3
{
printf("Hello, this is Callback_3: x = %d\n", x);
return 0;
}
int Handle(int y, int (*Callback)(int))
{
printf("Entering Handle Function.\n");
Callback(y);
printf("Leaving Handle Function.\n");
}
int main()
{
int a = 2;
int b = 4;
int c = 6;
printf("Entering Main Function.\n");
Handle(a, Callback_1);
Handle(b, Callback_2);
Handle(c, Callback_3);
printf("Leaving Main Function.\n");
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。同理,可使用多個參數的回調函數。
本文由--山卡拉少爺--首發於今日頭條