什么是回调函数?
什么是回调函数?
Call After比愚蠢的名字callback更合适。当或者如果函数内满足条件时,调用另一个接收为参数的函数——Call After函数。
与其在函数内部硬编写内部函数,不如编写一个函数以接收已编写的Call After函数作为参数。基于函数内代码检测到的状态更改,Call After可能会被调用。
回调函数是指定给现有函数/方法的一个函数,在某个动作完成、需要额外处理等情况下被调用。
例如,在Javascript中,尤其是在jQuery中,您可以指定回调参数,在动画完成时调用它。
在PHP中,preg_replace_callback()
函数允许您提供一个函数,该函数将在正则表达式匹配时被调用,并将匹配的字符串作为参数传递。
看这张图片 :)
主程序调用库函数(也可能是系统级函数),并传递回调函数名称。这个回调函数可以有多种实现方式。主程序根据需要选择一个回调。
最后,在执行过程中,库函数调用回调函数。
sort(int *arraytobesorted,void (*algorithmchosen)(void))
,它可以接受一个函数指针作为参数,该函数指针可用于在sort()
的实现中的某些点上使用。然后,被函数指针algorithmchosen
所引用的代码称为回调函数。 1. algorithmchosen = bubblesort
2. algorithmchosen = heapsort
3. algorithmchosen = mergesort ...
这些原型可能已经被实现,例如:
1. `void bubblesort(void)`
2. `void heapsort(void)`
3. `void mergesort(void)` ...
这是面向对象编程中实现多态性的概念。
回调是将一个函数作为参数传递给另一个函数,并在该过程完成后调用此函数的一种思想。
如果您通过以上精彩答案理解了回调的概念,我建议您应该了解其背后的思想。
“是什么让计算机科学家们开发回调?” 您可能会了解到一个问题,即阻塞(尤其是阻塞UI)。 而回调不是它的唯一解决方案。 还有很多其他解决方案(例如:线程、Futures、Promises...)。
在计算机编程中,“回调”是指对可执行代码的引用,或者是一段可执行代码,其作为参数传递给其他代码。这样可以使得一个更低级别的软件层调用在更高级别的层中定义的子例程(或函数)。
使用函数指针在C语言中实现回调
在C语言中,使用函数指针来实现回调。函数指针 - 顾名思义,是指向函数的指针。
例如,int (*ptrFunc) ();
在这里,ptrFunc是一个指向一个不带参数并返回整数的函数的指针。请不要忘记括号,否则编译器将认为ptrFunc是一个普通的函数名,它不带任何参数并返回一个整数指针。
以下是一些演示函数指针的代码。
#include<stdio.h>
int func(int, int);
int main(void)
{
int result1,result2;
/* declaring a pointer to a function which takes
two int arguments and returns an integer as result */
int (*ptrFunc)(int,int);
/* assigning ptrFunc to func's address */
ptrFunc=func;
/* calling func() through explicit dereference */
result1 = (*ptrFunc)(10,20);
/* calling func() through implicit dereference */
result2 = ptrFunc(10,20);
printf("result1 = %d result2 = %d\n",result1,result2);
return 0;
}
int func(int x, int y)
{
return x+y;
}
现在让我们尝试使用函数指针来理解C语言中的回调概念。
完整的程序包含三个文件:callback.c、reg_callback.h和reg_callback.c。
/* callback.c */
#include<stdio.h>
#include"reg_callback.h"
/* callback function definition goes here */
void my_callback(void)
{
printf("inside my_callback\n");
}
int main(void)
{
/* initialize function pointer to
my_callback */
callback ptr_my_callback=my_callback;
printf("This is a program demonstrating function callback\n");
/* register our callback function */
register_callback(ptr_my_callback);
printf("back inside main program\n");
return 0;
}
/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);
/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"
/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
printf("inside register_callback\n");
/* calling our callback function my_callback */
(*ptr_reg_callback)();
}
public interface Callback
{
public void notify(Result result);
}
调用者或更高级别的类
public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee
//Other functionality
//Call the Asynctask
ce.doAsynctask();
public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}
public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}
doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}
使用EventListener模式的回调
这种模式用于通知0到n个观察者/监听器,某个特定任务已经完成。
回调机制和EventListener/Observer机制的区别在于,在回调中,被调用方通知单个调用者,而在EventListener/Observer中,被调用方可以通知任何对该事件感兴趣的人(通知可能会去到应用程序的其他部分,而不是触发任务的部分)。
让我通过一个例子来解释。
事件接口
public interface Events {
public void clickEvent();
public void longClickEvent();
}
组件类 Widget
package com.som_itsolutions.training.java.exampleeventlistener;
import java.util.ArrayList;
import java.util.Iterator;
public class Widget implements Events{
ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>();
ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();
@Override
public void clickEvent() {
// TODO Auto-generated method stub
Iterator<OnClickEventListener> it = mClickEventListener.iterator();
while(it.hasNext()){
OnClickEventListener li = it.next();
li.onClick(this);
}
}
@Override
public void longClickEvent() {
// TODO Auto-generated method stub
Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
while(it.hasNext()){
OnLongClickEventListener li = it.next();
li.onLongClick(this);
}
}
public interface OnClickEventListener
{
public void onClick (Widget source);
}
public interface OnLongClickEventListener
{
public void onLongClick (Widget source);
}
public void setOnClickEventListner(OnClickEventListener li){
mClickEventListener.add(li);
}
public void setOnLongClickEventListner(OnLongClickEventListener li){
mLongClickEventListener.add(li);
}
}
按钮类
public class Button extends Widget{
private String mButtonText;
public Button (){
}
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}
复选框类
public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}
活动类
包 com.som_itsolutions.training.java.exampleeventlistener;
public class Activity implements Widget.OnClickEventListener
{
public Button mButton;
public CheckBox mCheckBox;
private static Activity mActivityHandler;
public static Activity getActivityHandle(){
return mActivityHandler;
}
public Activity ()
{
mActivityHandler = this;
mButton = new Button();
mButton.setOnClickEventListner(this);
mCheckBox = new CheckBox();
mCheckBox.setOnClickEventListner(this);
}
public void onClick (Widget source)
{
if(source == mButton){
mButton.setButtonText("Thank you for clicking me...");
System.out.println(((Button) mButton).getButtonText());
}
if(source == mCheckBox){
if(mCheckBox.isChecked()==false){
mCheckBox.setCheck(true);
System.out.println("The checkbox is checked...");
}
else{
mCheckBox.setCheck(false);
System.out.println("The checkbox is not checked...");
}
}
}
public void doSomeWork(Widget source){
source.clickEvent();
}
}
其他类别
public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}
主类
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}
虽然我来晚了13年,但在自己学习之后,我想在这里再回答一下这个问题,以防有人像我一样感到困惑。
其他回答已经总结了“回调函数”的核心问题:
它只是一个在完成某些操作时调用另一个函数的函数。
让我困惑的是例子,“你做了这个,现在做那个。” 像为什么我要那样使用它,当我可以直接调用一个方法或函数呢?
所以这里有一个快速、真实世界的例子,希望能让某个人“恍然大悟”。
超级伪代码
首先,你会遇到的核心问题是....
Multithreaded Method(Some arguments)
{
Do fancy multithreaded stuff....
}
Main()
{
Some stuff I wanna do = some tasks
Multhreaded Method(Some stuff I wanna do)
}
IsItDone = false
Callback()
{
print("Hey, I'm done")
IsItDone = true
}
Multithreaded Method(Some arguments, Function callback)
{
Do fancy multithreaded stuff....
}
Main()
{
Some stuff I wanna do = some tasks
Multhreaded Method(Some stuff I wanna do,Callback)
while(!IsItDone)
Wait a bit
}
这并不是最好的实现方式,我只是想给出一个清晰的例子。
所以这不仅是简单的“回调是什么?”而是“回调是什么?它对我有什么好处?”
一个重要的应用领域是,您可以将您的某个函数注册为句柄(即回调函数),然后发送消息/调用一些函数来完成一些工作或处理。现在,在处理完成后,被调用的函数会调用我们注册的函数(即回调已完成),从而告诉我们处理已完成。
这个维基百科链接通过图形方式很好地解释了回调。