前言:
而今小伙伴们对“回调函数的参数是怎么传的”可能比较关切,看官们都需要知道一些“回调函数的参数是怎么传的”的相关资讯。那么小编在网上汇集了一些有关“回调函数的参数是怎么传的””的相关内容,希望小伙伴们能喜欢,姐妹们一起来学习一下吧!“回调函数(callback),也叫call-after,但它的故事,远比它的名字更精彩”
01
最初的梦想
回调函数callback,也叫:call-after。相对于立刻调用而言,它意思就是回头再调用,或者叫:过一会再调用、事后调用。
立刻调用:这和编写普通函数一下,程序员在代码中写上一个函数,传递好参数,如果不出意外的话,CPU在运行到该行代码后,就会作函数调用,这种情况很直观,也非常好理解。
回头调用:或者叫事后调用(whatever,大家可以起一个更形象的名字),使用的场景稍微复杂一点:往往是一个函数,我们无法确定它的调用时机,例如:我们需要在用户点击一个按钮后,弹出一个对话框。但用户何时点击按钮是无法预测的!所以,弹出对话框的函数,最好是在GUI线程里面,由按钮响应函数onClick中调用:
//UI threadvoid onClick(){ openDialog();}
02
变味的回调
当然,这并不能让callback变得无法取代,真正让callback变得有点无法避免的原因是:函数onClick也不知道要调用哪个具体的函数。例如:用户点击按钮后,可能是需要弹出一个对话框,也可能是需要点亮一个LED,也可能是。。。不同的处理方法,往往对应着不同的处理函数。
这样,我们在为onClick准备回调函数的时候,往往是不确定的,为了应对这种变化,我们往往会预先设定一个回头再调用的函数,然后再交给用户交互(UI)线程决定什么时候调用:
void openDialog(){}void openLED(){}//Set callbackauto callback = openDialog;//or openLEDvoid onClick(){ callback(); //call callback}//UI threadvoid UIthread(){ ... onClick(); ...}
当然,最常见的形式,可能是这样的:把回调函数,以参数的形式传递给设置函数:
void onClick(auto callback)//auto是函数指针类型{ callback();}//UI threadvoid UIthread(){ ... onClick(openLED);//Set/Call callback ...}
这样,就让onClick函数具备了事后处理任何事情的能力。需要处理什么事情,就传递该事情的处理函数地址就好,当然,如果胆敢给个非法地址的话,那segmentation fault也会如约而至。
这个时候,建议大家看一下文章《CPU眼里的:函数指针》,它是回调函数可以成立的技术基础。
当然,这种使用场景下,已经跟callback的字面意思相差甚远了。倒是让callback差点成为了“函数指针”的代名词。但习惯的力量是巨大的,所以callback也就一直这么叫下去了。
03
总结
今天我们再讨论回调函数的时候,往往需要具备两个条件:事前准备和事后调用。也就是事前准备:调用哪个函数;和在等某件事情发生后,由事后处理函数,调用事前准备好的函数。使用回调函数的地方,往往会涉及到两个线程,一个是事前准备的线程,也就是预设回调函数的线程;另外一个是事后处理线程,也就是真正调用回调函数的线程。函数指针,也就是被调函数的内存首地址,它往往作为一个函数参数,传递给事后处理函数备用。不同的参数,往往对应着不同的被调函数。这种设计方式,让被调函数的选择面极广,可以根据不同的情况,准备不同的回调函数。这让程序变得更加灵活、有弹性。
最后,回调函数,撕裂了代码的逻辑,往往一到函数指针,代码的逻辑线就断了。因为,事前准备回调函数的线程逻辑,跟事后调用回调函数的线程逻辑,往往是两个不同的故事。
标签: #回调函数的参数是怎么传的