什么是回调函数?相信很多人都似懂非懂,半懂不懂,今天就通俗易懂的讲解回调函数,让你能理解回调函数的大部分作用及意义。
目录
定义
先上常规的定义:
回调函数也是一个函数。与一般函数直接调用区别在于,使用回调函数的过程,是一个函数将另一个函数作为参数调用。而被用来调用的那个函数,就是回调函数。
具体的实例,此处的cmp这个函数就是作为sort函数的参数来使用!
形象的例子
以下是通俗的解释:
回调,其实就是callback的英文翻译:
callback
也就是call back
通俗理解,call back:打回去
你去店里买东西,老板说没货了,让你留一个联系你的方法,(这个方法包含一些具体怎么做,比如几点可以联系你,用wx还是电话),到货了就使用这个方法来通知你。
换句话说,就是顾客留下了打电话给顾客的一个具体的方法(即函数),然后由商家去调用这个方法。
代码解释
接下来细致的讲解:
一般来说函数的参数都是普通的什么int型
但是我们也可以让函数的参数,是一个函数,例如:
各个语言的回调函数的语法格式各不相同,因此此处使用伪代码的形式:
funcB(int a){
print(a);
}
funcA(funcB){
funcB();
}
上面的伪代码让A的参数包含了B这个函数,然后让A去调用B这个函数。
我们就可以看到,其实所谓的回调函数,与普通函数的区别在于,我们将这个函数的调用权利,交给了别的函数内部来调用,而不是我们自己去直接调用。
我们调用了A这个函数,然后A去调用B函数,B函数是被间接调用的,这个被间接调用的就是B函数。
(上面将函数当作参数的方法,这里的写法并不规范,不同语言中有不同的写法。在c里面是函数指针,在C#里是委托)
用处及完整代码例子
那这样有什么用呢?
那么它相比普通的函数间互相调用的方法有什么好处呢?
1.增加了代码的灵活性,可以介入一些系统本来就提供的函数间的运行过程。
以往的代码,参数都仅仅是一些对象,而将函数作为参数可以增加灵活性。
具体来说,就例如,我们如果需要排序,那我们怎么做呢,自己写一个肯定很麻烦。
我们可以调用系统的Sort函数
例如:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
// 方式一、使用数组
int a[10] = {9, 6, 3, 8, 5, 2, 7, 4, 1, 0};
sort(a, a + 10); // 10为元素个数
return 0;
}
这样可以实现一个升序排序的效果。
但如果我们要实现降序排序呢?怎么办?不可能自己写一个降序排序吧。
我们希望告诉系统的sort函数,你这次排序给我按照降序排序的规则来做。我们也就是传达一个消息给系统,如何传达呢?
就是我们自己写一个排序规则的函数,然后作为参数传给系统:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
bool cmp(int num1, int num2) {
return num1 > num2; // 可以简单理解为 >: 降序排列; < : 升序排列
}
int main() {
// 一、使用数组
int a[10] = {9, 6, 3, 8, 5, 2, 7, 4, 1, 0};
sort(a, a + 10, cmp); // 使用自定义排序函数
return 0;
}
可以看到,此处的cmp就是一个回调函数!它写出来后,我们没有亲自调用过它,而是将它作为参数,传达给系统的这个Sort函数,告诉它让它按照我们的这个规则来做。
这样我们就可以在不修改系统给定的Sort函数的情况下去介入这个Sort的过程!这就是回调函数的意义所在。
再例如更为复杂的排序规则,包含有结构体的情况,我们希望按照某个结构体的某个属性来排序:
比如既可以按照name排序,也可以按照grade排序
struct Student { // 学生结构体
string name; // 学生姓名
int grade; // 学生分数
Student(); // 无参数构造函数
Student(string name, int grade) : name(name), grade(grade) {}; // 有参数构造函数
};
那么写法如下:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct Student { // 学生结构体
string name; // 学生姓名
int grade; // 学生分数
Student(); // 无参数构造函数
Student(string name, int grade) : name(name), grade(grade) {}; // 有参数构造函数
};
bool cmp(Student s1, Student s2) { // 自定义排序
if (s1.grade != s2.grade) { // 如果学生成绩不同
return s1.grade > s2.grade; // 则按照成绩降序排列
}
return s1.name < s2.name; // 否则按照姓名升序排列
}
int main() {
vector<Student> studs;
studs.emplace_back("Bob", 80);
studs.emplace_back("Ali", 90);
studs.emplace_back("Ann", 85);
studs.emplace_back("Liming", 90);
studs.emplace_back("Trump", 79);
studs.emplace_back("Fury", 58);
studs.emplace_back("Jam", 62);
studs.emplace_back("Lucy", 89);
sort(studs.begin(), studs.end(), cmp); // 排序
for (int i = 0; i < studs.size(); i++) { // 输出结果
cout << studs[i].name << "\t" << studs[i].grade << endl;
}
return 0;
}
回调函数还有其他的作用,例如在适当的时机通知函数使其调用,还可以提高运行的效率。
以及还有其他的用途,如同步回调,异步回调、以及回调地狱,在后续的文章我会进行讲解(可能),欢迎关注我的博客。