————這篇文章會隨着學習逐步更新,同時和Java接口回調配合記錄————
回調函數
回調函數是一個時時聽到的概念,比如在windows API編程時遇到的WinProc函數,就是我們編寫而由操作系統調用的函數。現在,我們需要慢慢又詳細的記錄一下這個問題。
庫與使用者的問題
在開始之前,首先我們想像這樣一個情景,一個大型軟件公司開發一套軟件庫提供給用戶使用。在這句話中,出現兩個對立面,一個是軟件公司,一個是用戶。顯然,軟件公司實力很強大,他們強大的地方在於他們很聰明。請看下圖:
庫開發者是提供方,他們不知道用戶想做什么,庫開發者對用戶的信息是未知的,因為兩邊的人誰也沒見過誰,就像一個人在美國一個人在中國。他們聰明的地方就在於即使不知道用戶怎么操作,他們也可以用一種通用的方法來解決用戶的問題。換句話說,庫開發方不管用戶怎么折騰變化,他都能適應。這就是問題的神奇之處,當然,為了達到這種效果,必須有一種規則來約束。
規則
現在來說規則,規則比較好理解,就是兩方達成的約束。比如甲和乙兩個人,甲對乙說,你只要提供給我一個塑料球,我都能給它塗上顏色。這里的約束是塑料球,(當然,為了簡化問題這里的約束還是比較泛泛而不嚴謹的),這個時候如果乙給他一個水晶球,或者給他一輛汽車都不行,因為已經超越了約束。所以說,庫開發者能適應用戶的各種變化就在於他也給了用戶一定的約束,是在約束之下的適應,這也是不言自明的。
代碼之下無秘密
下面一段代碼極好的解釋了上述問題:
#include <stdio.h> typedef int student_id; typedef int student_age; typedef struct _Student{ student_id id; student_age age; }Student; //類型重定義:函數指針類型 typedef bool (*pFun)(Student, Student); //----------------------------------------------- //冒泡排序法:能夠按AGE或ID排序,用同一個函數實現 //----------------------------------------------- void sort(Student stu[],const int num,pFun fun) { Student temp; for(int i = 0; i < num; ++i)
{ for(int j = 0; j < num - i -1; ++j) { if((*fun)(stu[j],stu[j+1])) { temp = stu[j]; stu[j] = stu[j+1]; stu[j+1] = temp; } } } } //----------------------------------------------- //回調函數:比較年齡 //----------------------------------------------- bool CompareAge(Student stu1,Student stu2) { //更改從大到小還是從小到大的順序,只需反一下。 if(stu1.age < stu2.age) return true; return false; } //----------------------------------------------- //回調函數:比較id //----------------------------------------------- bool CompareId(Student stu1,Student stu2) { //更改從大到小還是從小到大的順序,只需反一下。 if(stu1.id < stu2.id) return true; return false; } int main() { Student stu[] = { {1103,24}, {1102,23}, {1104,22}, {1107,25}, {1105,21}}; pFun fun = CompareAge; int size = sizeof(stu)/sizeof(Student); sort(stu,size,fun); for(int i = 0; i < size; ++i){ printf("%d %d\n",stu[i].id,stu[i].age); } return 0; }
通過代碼,我們必須分辨出哪個是庫提供方,哪個是用戶:
sort(...)方法是庫開者提供的,只是因為模擬問題所以把它寫在一個文件中了,我們可以假想它存放在某個靜態庫lib里面,這樣就和它有了界限。
庫開發者提供方法sort(...)供我們調用,形參里面還包括一個函數指針,就是調用用戶自己寫的函數,也即回調函數。所以它提供了規則,也就是說這個回調函數的形參是什么,返回值又是什么,假如用戶對於這個回調函數的形參和返回值啥都不知道,隨意寫了一個函數放進去,sort方法能接受嗎?顯然是不行的。
那么用戶怎么知道回調函數的形參和返回值等信息呢?庫開發方會告知,或者在它的文檔里面會有說明,就像在windows API開發窗口程序時提供的WinProc() 函數一樣,里面的形參必須一模一樣。(這個地方會牽涉到接口)
什么是回?
根據上面的代碼,我們知道,庫開發方提供了一個方法,然后形參又帶有一個函數指針,等着用戶去寫然后拿來調用,並在其實現中調用了這個函數。站在庫開發方的立場,我們可以總結為一句話:庫開發方調用了用戶的函數(回調函數)。
現在,我們把視角移到回調函數的立場上來看,它被調用了。但同時它也有參數,且傳進來的參數是庫開發方提供的數據,這里我們又可以總結一句話:回調函數調用了庫開發方的數據。
這就是“回”的意思,你調我我也調用你,雙方互相調用。
回調函數的重點是什么?
根據上文分析,發現回調函數其實也不是難於理解,我覺得重點在於一定要划分清楚誰是庫開發方(也可稱為提供方,調用者),誰是用戶,把職能划分清楚是最關鍵的。
2018-01-22 12:46:14