通俗易懂的讲解回调函数,保证让你看懂callback

什么是回调函数?相信很多人都似懂非懂,半懂不懂,今天就通俗易懂的讲解回调函数,让你能理解回调函数的大部分作用及意义。

目录

定义

形象的例子

代码解释

用处及完整代码例子


定义

先上常规的定义:

回调函数也是一个函数。与一般函数直接调用区别在于,使用回调函数的过程,是一个函数将另一个函数作为参数调用。而被用来调用的那个函数,就是回调函数。

具体的实例,此处的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;
}

回调函数还有其他的作用,例如在适当的时机通知函数使其调用,还可以提高运行的效率。

以及还有其他的用途,如同步回调,异步回调、以及回调地狱,在后续的文章我会进行讲解(可能),欢迎关注我的博客。

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值