Qu'est-ce qu'une fonction de rappel?


685

Qu'est-ce qu'une fonction de rappel?


8
vous pouvez trouver ici: stackoverflow.com/a/9652434/3343174 la meilleure explication sur les rappels
Fakher


Regardez la deuxième réponse pour une explication détaillée
Donato

La meilleure explication du rappel que j'ai jamais trouvée youtube.com/watch?v=xHneyv38Jro
Sameer Sinha

Réponses:


683

Les développeurs sont souvent confus par ce qu'est un rappel à cause du nom de la maudite chose.

Une fonction de rappel est une fonction qui est:

  • accessible par une autre fonction, et
  • est invoqué après la première fonction si cette première fonction se termine

Une bonne façon d'imaginer comment fonctionne une fonction de rappel est qu'il s'agit d'une fonction qui est " appelée à l'arrière " de la fonction dans laquelle elle est passée.

Peut-être qu'un meilleur nom serait une fonction "appel après" .

Cette construction est très utile pour un comportement asynchrone où nous voulons qu'une activité ait lieu à la fin d'un événement précédent.

Pseudocode:

// A function which accepts another function as an argument
// (and will automatically invoke that function when it completes - note that there is no explicit call to callbackFunction)
funct printANumber(int number, funct callbackFunction) {
    printout("The number you provided is: " + number);
}

// a function which we will use in a driver function as a callback function
funct printFinishMessage() {
    printout("I have finished printing numbers.");
}

// Driver method
funct event() {
   printANumber(6, printFinishMessage);
}

Résultat si vous avez appelé event ():

The number you provided is: 6
I have finished printing numbers.

L'ordre de sortie ici est important. Étant donné que les fonctions de rappel sont appelées par la suite, "J'ai terminé l'impression des numéros" est imprimé en dernier, pas en premier.

Les rappels sont appelés ainsi en raison de leur utilisation avec les langages de pointeurs. Si vous n'en utilisez pas, ne vous occupez pas du nom «rappel». Comprenez simplement que ce n'est qu'un nom pour décrire une méthode fournie comme argument à une autre méthode, de telle sorte que lorsque la méthode parent est appelée (quelle que soit la condition, comme un clic sur un bouton, une minuterie, etc.) et que son corps de méthode se termine, la fonction de rappel est alors invoquée.

Certains langages prennent en charge les constructions où plusieurs arguments de fonction de rappel sont pris en charge et sont appelés en fonction de la façon dont la fonction parent se termine (c'est-à-dire qu'un rappel est appelé dans le cas où la fonction parent se termine avec succès, un autre est appelé dans le cas où la fonction parent lance un erreur spécifique, etc.).


31
Votre exemple est génial mais je ne vois pas pourquoi la terminologie est "rappel". Quand est-ce que senseOfLife est "rappelé"?
CodyBugstein

4
Bonjour là-bas, environ once its parent method completes, the function which this argument represents is then called. Donc, si la fonction est passée à une autre fonction comme argument mais appelée à partir du milieu du runtime de la fonction parent comme parent(cb) {dostuff1(); cb(); dostuff2()}alors elle n'est pas considérée comme une callbackfonction?
Max Yari du

2
@MaxYari: À mon humble avis, il est toujours considéré comme un rappel.L'important ici est que la fonction parent va utiliser la fonction d'entrée (alias rappel) d'une manière ou d'une autre. Il peut être appelé au milieu ou à la fin ou si une condition est remplie.
Kamran Bigdely

12
@ 8bitjunkie merci - mais où est la méthode senseOfLife invoquée dans la fonction printANumber?
BKSpurgeon

2
Ce n'est pas vrai du tout: "est automatiquement invoqué après la fin de la première fonction". Un rappel n'a pas du tout à être exécuté, encore moins automatiquement. En fait, il n'est pas rare que les rappels se terminent avant la fin de la fonction parent. Je n'aime pas beaucoup la façon dont les gens décrivent les rappels comme des fonctions exécutées "plus tard". C'est très déroutant pour les gens qui apprennent à leur sujet. Autrement dit, les rappels ne sont que des fonctions qui sont passées comme arguments à d'autres fonctions. Période. Une meilleure explication consisterait à expliquer POURQUOI les rappels sur les références de fonction.
Jordanie

226

Définition opaque

Une fonction de rappel est une fonction que vous fournissez à un autre morceau de code, lui permettant d'être appelée par ce code.

Exemple artificiel

Pourquoi voudriez-vous faire ça? Disons qu'il y a un service que vous devez invoquer. Si le service revient immédiatement, vous venez de:

  1. Appeler
  2. Attendez le résultat
  3. Continuez une fois le résultat entré

Par exemple, supposons que le service soit la factorialfonction. Lorsque vous voulez la valeur de 5!, vous appelez factorial(5)et les étapes suivantes se produisent:

  1. Votre emplacement d'exécution actuel est enregistré (sur la pile, mais ce n'est pas important)

  2. L'exécution est confiée à factorial

  3. Une fois factorialterminé, il place le résultat quelque part où vous pouvez y accéder

  4. L'exécution revient là où elle était [1]

Supposons maintenant que cela factorialprenne beaucoup de temps, car vous lui donnez des nombres énormes et il doit fonctionner sur un cluster de super-informatique quelque part. Disons que vous vous attendez à ce que cela prenne 5 minutes pour retourner votre résultat. Vous pourriez:

  1. Gardez votre conception et exécutez votre programme la nuit lorsque vous dormez, afin de ne pas regarder l'écran la moitié du temps

  2. Concevez votre programme pour faire d'autres choses tout en factorialfaisant son travail

Si vous choisissez la deuxième option, les rappels peuvent fonctionner pour vous.

Conception de bout en bout

Afin d'exploiter un modèle de rappel, ce que vous voulez, c'est pouvoir appeler factorialde la manière suivante:

factorial(really_big_number, what_to_do_with_the_result)

Le second paramètre,, what_to_do_with_the_resultest une fonction à laquelle vous envoyez factorial, dans l'espoir de factoriall'appeler sur son résultat avant de revenir.

Oui, cela signifie que cela factorialdoit avoir été écrit pour prendre en charge les rappels.

Supposons maintenant que vous souhaitiez pouvoir passer un paramètre à votre rappel. Maintenant, vous ne pouvez pas, parce que vous n'allez pas l'appeler, factorialoui. Il factorialfaut donc l'écrire pour vous permettre de passer vos paramètres, et il les remettra simplement à votre rappel quand il l'invoquera. Cela pourrait ressembler à ceci:

factorial (number, callback, params)
{
    result = number!   // i can make up operators in my pseudocode
    callback (result, params)
}

Maintenant que factorialcela autorise ce modèle, votre rappel pourrait ressembler à ceci:

logIt (number, logger)
{
    logger.log(number)
}

et votre appel factorialserait

factorial(42, logIt, logger)

Et si vous voulez retourner quelque chose logIt? Eh bien, vous ne pouvez pas, parce que vous factorialn'y prêtez pas attention.

Eh bien, pourquoi ne pouvez-vous pas factorialsimplement renvoyer ce que votre rappel renvoie?

Rendre non bloquant

Étant donné que l'exécution est censée être remise au rappel une fois factorialterminé, il ne devrait vraiment rien retourner à son appelant. Et idéalement, il lancerait en quelque sorte son travail dans un autre thread / processus / machine et reviendrait immédiatement afin que vous puissiez continuer, peut-être quelque chose comme ceci:

factorial(param_1, param_2, ...)
{
    new factorial_worker_task(param_1, param_2, ...);
    return;
}

Il s'agit maintenant d'un "appel asynchrone", ce qui signifie que lorsque vous l'appelez, il revient immédiatement mais n'a pas encore vraiment fait son travail. Vous avez donc besoin de mécanismes pour le vérifier et pour obtenir son résultat une fois terminé, et votre programme est devenu plus complexe dans le processus.

Et en passant, en utilisant ce modèle, le factorial_worker_taskpeut lancer votre rappel de manière asynchrone et revenir immédiatement.

Donc que fais-tu?

La réponse est de rester dans le modèle de rappel. Chaque fois que vous voulez écrire

a = f()
g(a)

et fdoit être appelé de manière asynchrone, vous écrirez à la place

f(g)

gest passé en tant que rappel.

Cela change fondamentalement la topologie de flux de votre programme et prend un certain temps pour s'y habituer.

Votre langage de programmation pourrait vous aider beaucoup en vous donnant un moyen de créer des fonctions à la volée. Dans le code immédiatement ci-dessus, la fonction gpeut être aussi petite que print (2*a+1). Si votre langue nécessite que vous définissiez cela comme une fonction distincte, avec un nom et une signature entièrement inutiles, votre vie va devenir désagréable si vous utilisez beaucoup ce modèle.

Si, en revanche, votre langage vous permet de créer des lambdas, alors vous êtes en bien meilleure forme. Vous finirez alors par écrire quelque chose comme

f( func(a) { print(2*a+1); })

ce qui est tellement plus agréable.

Comment passer le rappel

Comment transmettriez-vous la fonction de rappel factorial? Eh bien, vous pouvez le faire de plusieurs façons.

  1. Si la fonction appelée s'exécute dans le même processus, vous pouvez passer un pointeur de fonction

  2. Ou peut-être que vous souhaitez conserver un dictionnaire de fn name --> fn ptrdans votre programme, auquel cas vous pouvez passer le nom

  3. Peut-être que votre langage vous permet de définir la fonction sur place, possible comme lambda! En interne, il crée une sorte d'objet et passe un pointeur, mais vous n'avez pas à vous en soucier.

  4. Peut-être que la fonction que vous appelez s'exécute sur une machine entièrement distincte, et vous l'appelez en utilisant un protocole réseau comme HTTP. Vous pouvez exposer votre rappel en tant que fonction appelable HTTP et transmettre son URL.

Vous avez eu l'idée.

La récente augmentation des rappels

Dans cette ère du Web dans laquelle nous sommes entrés, les services que nous invoquons sont souvent sur le réseau. Souvent, nous n'avons aucun contrôle sur ces services, c'est-à-dire que nous ne les avons pas écrits, nous ne les maintenons pas, nous ne pouvons pas nous assurer qu'ils fonctionnent ou qu'ils fonctionnent.

Mais nous ne pouvons pas nous attendre à ce que nos programmes se bloquent en attendant que ces services répondent. Conscients de cela, les fournisseurs de services conçoivent souvent des API en utilisant le modèle de rappel.

JavaScript supporte très bien les rappels, par exemple avec les lambdas et les fermetures. Et il y a beaucoup d'activité dans le monde JavaScript, aussi bien sur le navigateur que sur le serveur. Il existe même des plates-formes JavaScript en cours de développement pour mobile.

À mesure que nous progressons, de plus en plus d'entre nous écriront du code asynchrone, pour lequel cette compréhension sera essentielle.


1
Un concept très bien expliqué ..! :)
piyushGoyal

Grande explication, +1.
Lingamurthy CS

1
C'est la meilleure réponse parmi toutes les autres. Veuillez le voter.
Abhishek Nalin

3
Expliqué parfaitement et tout est expliqué. J'aimerais pouvoir voter à nouveau.
Yogesh Yadav

Oui, je comprends comment fonctionnent les lambas en javascript et en rubis. Et java 8, mais les anciennes versions de java n'utilisaient pas de lambas et utilisaient plutôt des classes et j'aimerais savoir comment ce genre de rappel fonctionne. Encore une réponse supérieure à l'autre.
Donato

97

Notez que le rappel est un mot.

La page de rappel de wikipedia l' explique très bien.

citation de la page wikipedia:

En programmation informatique, un rappel est une référence au code exécutable, ou un morceau de code exécutable, qui est passé comme argument à un autre code. Cela permet à une couche logicielle de niveau inférieur d'appeler un sous-programme (ou une fonction) défini dans une couche de niveau supérieur.


14
Belle façon de présenter une réponse.
Chathuranga Chandrasekara

1
Et cela conduit également à la réponse d'une manière différente. Le nom "rappel" est ce qui a été "rappelé", de la même manière que quelque chose qui a été arrêté a été arrêté et quelque chose qui est utilisé pour se connecter est une connexion.
Anonyme

22
Cela aurait pu être un commentaire - en gros, c'est un lien vers Wikipedia
CodyBugstein

Wikipedia a en fait des trucs de programmation vraiment géniaux dans ses troves. J'ai toujours pensé que le terme "rappel" était mieux expliqué en utilisant la phrase "Je vais rappeler à ..."
Thomas

Grande explication sur javascriptissexy.com/…; que je republierai ici; Une fonction de rappel est une fonction qui est passée à une autre fonction en tant que paramètre, et la fonction de rappel est appelée ou exécutée dans l'autre fonction. // Notez que l'élément dans le paramètre de la méthode click est une fonction, pas une variable. // L'élément est une fonction de rappel $ ("# btn_1"). Click (function () {alert ("Btn 1 Clicked" );}); Comme vous le voyez dans l'exemple précédent, nous passons une fonction comme paramètre à la méthode click pour qu'elle s'exécute -
MarcoZen

46

Une réponse simple serait qu'il s'agit d'une fonction qui n'est pas appelée par vous mais plutôt par l'utilisateur ou par le navigateur après qu'un certain événement s'est produit ou après qu'un certain code a été traité.


42

Une fonction de rappel est celle qui doit être appelée lorsqu'une certaine condition est remplie. Au lieu d'être appelée immédiatement, la fonction de rappel est appelée à un certain moment dans le futur.

Il est généralement utilisé lors du démarrage d'une tâche qui se terminera de manière asynchrone (c'est-à-dire se terminera un certain temps après le retour de la fonction appelante).

Par exemple, une fonction pour demander une page Web peut exiger que son appelant fournisse une fonction de rappel qui sera appelée lorsque le téléchargement de la page Web sera terminé.


Dans votre première phrase, vous dites "...when a condition is met"mais je pensais que les rappels sont appelés lorsque la fonction parent a terminé son exécution et ne dépendent pas des conditions (?).
Ojonugwa Jude Ochalifu

La «certaine condition» signifie simplement qu'ils sont généralement appelés pour une raison plutôt que par hasard. Un rappel peut être appelé lorsque le parent / créateur est toujours en cours d'exécution - cela peut entraîner une condition de concurrence critique si le programmeur ne s'y attend pas.
Thomas Bratt

Merci pour la clarification
Ojonugwa Jude Ochalifu

34

Les rappels sont plus facilement décrits en termes de système téléphonique. Un appel de fonction est analogue à appeler une personne au téléphone, à lui poser une question, à obtenir une réponse et à raccrocher; l'ajout d'un rappel modifie l'analogie de sorte qu'après lui avoir posé une question, vous lui donnez également votre nom et votre numéro afin qu'elle puisse vous rappeler avec la réponse.

- Paul Jakubik, "Implémentations de rappel en C ++"


1
Donc mon nom et mon numéro sont une fonction?
Koray Tugay

Non, ce serait l'analogie si "rappel" était un bon nom pour ce qui est à la place: vous demandez à l'opérateur téléphonique de faire un appel. La fin.
gherson

33

Je crois que ce jargon de "rappel" a été utilisé à tort dans de nombreux endroits. Ma définition serait quelque chose comme:

Une fonction de rappel est une fonction que vous transmettez à quelqu'un et lui permettez de l'appeler à un moment donné.

Je pense que les gens viennent de lire la première phrase de la définition du wiki:

un rappel est une référence au code exécutable, ou un morceau de code exécutable, qui est passé comme argument à un autre code.

J'ai travaillé avec de nombreuses API, voir divers mauvais exemples. Beaucoup de gens ont tendance à nommer un pointeur de fonction (une référence au code exécutable) ou des fonctions anonymes (un morceau de code exécutable) "rappel", si ce ne sont que des fonctions, pourquoi avez-vous besoin d'un autre nom pour cela?

En fait, seule la deuxième phrase de la définition du wiki révèle les différences entre une fonction de rappel et une fonction normale:

Cela permet à une couche logicielle de niveau inférieur d'appeler un sous-programme (ou une fonction) défini dans une couche de niveau supérieur.

donc la différence est qui vous allez passer la fonction et comment votre fonction passée va être appelée. Si vous venez de définir une fonction et de la passer à une autre fonction et de l'appeler directement dans ce corps de fonction, ne l'appelez pas un rappel. La définition indique que votre fonction passée sera appelée par la fonction "de niveau inférieur".

J'espère que les gens peuvent arrêter d'utiliser ce mot dans un contexte ambigu, cela ne peut pas aider les gens à mieux comprendre que pire.


2
Votre réponse est logique ... mais j'ai du mal à l'imaginer. Pouvez-vous donner un exemple?
CodyBugstein

3
@Zane Wong :: Dans le dernier vous avez écrit "La définition dit que votre fonction passée sera appelée par la fonction" de niveau inférieur "." Pouvez-vous expliquer ce que la fonction de niveau inférieur indique? C'est mieux si vous donnez un exemple.
Viku

Un exemple aurait été bien
Yousuf Azad

1
Je pense que la différence entre l'appel de fonction classique et le style de rappel est liée à une direction dépendante: si le module A dépend du module ("utilise") B, A appelle une fonction de B, ce n'est pas un rappel. Si A passe une référence à sa fonction à B, alors B appelle une fonction de A, c'est un rappel: l'appel revient en arrière par rapport à la dépendance du module.
XouDo

30

Restons simples. Qu'est-ce qu'une fonction de rappel?

Exemple par parabole et analogie

J'ai une secrétaire. Chaque jour, je lui demande: (i) de déposer le courrier sortant de l'entreprise au bureau de poste, et après qu'elle l'ait fait, de faire: (ii) toute tâche que j'ai écrite pour elle sur une de ces notes autocollantes .

Maintenant, quelle est la tâche sur le pense-bête? La tâche varie d'un jour à l'autre.

Supposons que ce jour-là, je lui demande d'imprimer certains documents. J'écris donc cela sur le pense-bête, et je l'épingle sur son bureau avec le courrier sortant qu'elle doit poster.

En résumé:

  1. d'abord, elle doit déposer le courrier et
  2. immédiatement après cela, elle doit imprimer certains documents.

La fonction de rappel est cette deuxième tâche: imprimer ces documents. Parce que c'est fait APRÈS que le courrier soit déposé, et aussi parce que le pense-bête lui disant d'imprimer le document lui est remis avec le courrier qu'elle doit poster.

Lions maintenant cela avec le vocabulaire de programmation

  • Dans ce cas, le nom de la méthode est: DropOffMail.
  • Et la fonction de rappel est: PrintOffDocuments. PrintOffDocuments est la fonction de rappel car nous voulons que le secrétaire le fasse, uniquement après l'exécution de DropOffMail.
  • Je voudrais donc "passer: PrintOffDocuments comme un" argument "à la méthode DropOffMail. C'est un point important.

C'est tout. Rien de plus. J'espère que cela vous a éclairé - et sinon, postez un commentaire et je ferai de mon mieux pour clarifier.


18

Cela fait sonner les rappels comme des instructions de retour à la fin des méthodes.

Je ne suis pas sûr que ce soit ça.

Je pense que les rappels sont en fait un appel à une fonction, à la suite d'une autre fonction appelée et terminée.

Je pense aussi que les rappels sont destinés à répondre à l'invocation d'origine, dans une sorte de "hé! Cette chose que vous avez demandée?


1
+1 pour remettre en question les rappels et les déclarations de retour. Avant, je me faisais prendre par cela et beaucoup de diplômés avec qui je travaille.
8bitjunkie

2
Bonne réponse - m'a aidé à le comprendre contrairement à beaucoup d'autres réponses!
2014

18

Qu'est-ce que le rappel ?

  • En général, un appel téléphonique est passé pour retourner celui que quelqu'un a reçu.
  • En informatique, un rappel est un morceau de code exécutable qui est passé en argument à un autre code. Lorsque la fonction a terminé son travail (ou lorsqu'un événement s'est produit), elle appelle votre fonction de rappel (elle vous rappelle - d'où le nom).

Qu'est-ce qu'une fonction de rappel ?

  • une fonction de rappel est comme un Serviteur qui "rappelle" à son Maître quand il a terminé une tâche.
  • une fonction de rappel est une fonction qui est passée à une autre fonction (appelons cette autre fonction otherFunction) en tant que paramètre, et la fonction de rappel est appelée (ou exécutée) à l'intérieur du otherFunction.
    function action(x, y, callback) {
        return callback(x, y);
    }

    function multiplication(x, y) {
        return x * y;
    }

    function addition(x, y) {
        return x + y;
    }

    alert(action(10, 10, multiplication)); // output: 100

    alert(action(10, 10, addition)); // output: 20

Dans SOA, le rappel permet aux modules d'extension d'accéder aux services à partir du conteneur / de l'environnement.

Analogie: rappels. Asynchrone. Exemple réel non bloquant
pour le rappel


Une fonction de rappel n'est pas elle-même une fonction d'ordre supérieur. Il est passé à une fonction d'ordre supérieur.
danio

17

Appel après serait un meilleur nom que le nom stupide, rappel . Lorsque ou si la condition est remplie dans une fonction, appelez une autre fonction, la fonction Appel après , celle reçue en argument.

Plutôt que de coder en dur une fonction interne dans une fonction, on écrit une fonction pour accepter comme argument une fonction Call After déjà écrite . L' appel après peut être appelé en fonction des changements d'état détectés par le code dans la fonction recevant l'argument.


C'est une bonne idée. Je suis allé chercher "appelé à l'arrière" pour essayer d'expliquer cela. Je pouvais voir quelqu'un comme Martin Fowler vulgariser "appeler après" comme nouveau terme pour ces derniers sur son blog fondateur.
8bitjunkie

15

Une fonction de rappel est une fonction que vous spécifiez pour une fonction / méthode existante, à appeler lorsqu'une action est terminée, nécessite un traitement supplémentaire, etc.

En Javascript, ou plus spécifiquement jQuery, par exemple, vous pouvez spécifier un argument de rappel à appeler à la fin d'une animation.

En PHP, la preg_replace_callback()fonction vous permet de fournir une fonction qui sera appelée lorsque l'expression régulière est mise en correspondance, en passant la ou les chaînes mises en correspondance comme arguments.


10

regardez l'image :)Voilà comment cela fonctionne

Le programme principal appelle la fonction de bibliothèque (qui peut également être une fonction de niveau système) avec le nom de la fonction de rappel. Cette fonction de rappel peut être implémentée de plusieurs manières. Le programme principal choisit un rappel selon les exigences.

Enfin, la fonction de bibliothèque appelle la fonction de rappel pendant l'exécution.


7
Pourriez-vous également ajouter une explication textuelle à cela? Si l'image disparaît, cette réponse perd tout contexte.
Tim Post

le texte d'autres personnes l'explique le mieux. la seule chose qui me manquait est l'image :)

De toutes les descriptions longues que j'ai vues ici, celle-ci est celle qui m'a fait dire "ahhhhh, maintenant je vois son utilisation". Ayez un vote positif.
DiBosco

7

La réponse simple à cette question est qu'une fonction de rappel est une fonction qui est appelée via un pointeur de fonction. Si vous passez le pointeur (adresse) d'une fonction comme argument à un autre, lorsque ce pointeur est utilisé pour appeler la fonction vers laquelle il pointe, il est dit qu'un rappel est effectué


7

Supposons que nous ayons une fonction sort(int *arraytobesorted,void (*algorithmchosen)(void))où il peut accepter un pointeur de fonction comme argument qui peut être utilisé à un moment donné de sort()l'implémentation de. Ensuite, ici, le code qui est adressé par le pointeur de fonction algorithmchosenest appelé comme fonction de rappel .

Et voyez l'avantage est que nous pouvons choisir n'importe quel algorithme comme:

  1.    algorithmchosen = bubblesort
  2.    algorithmchosen = heapsort
  3.    algorithmchosen = mergesort   ...

Qui ont été, par exemple, ont été mis en œuvre avec le prototype:

  1.   `void bubblesort(void)`
  2.   `void heapsort(void)`
  3.   `void mergesort(void)`   ...

Ceci est un concept utilisé pour atteindre le polymorphisme dans la programmation orientée objet


Grande explication sur javascriptissexy.com/…; que je republierai ici; Une fonction de rappel est une fonction qui est passée à une autre fonction en tant que paramètre, et la fonction de rappel est appelée ou exécutée dans l'autre fonction. // Notez que l'élément dans le paramètre de la méthode click est une fonction, pas une variable. // L'élément est une fonction de rappel $ ("# btn_1"). Click (function () {alert ("Btn 1 Clicked" );}); Comme vous le voyez dans l'exemple précédent, nous passons une fonction comme paramètre à la méthode click pour qu'elle s'exécute -
MarcoZen

4

«En programmation informatique, un rappel est une référence au code exécutable, ou un morceau de code exécutable, qui est passé comme argument à un autre code. Cela permet à une couche logicielle de niveau inférieur d'appeler un sous-programme (ou une fonction) défini dans une couche de niveau supérieur. » - Wikipédia

Rappel en C à l'aide du pointeur de fonction

En C, le rappel est implémenté à l'aide du pointeur de fonction. Pointeur de fonction - comme son nom l'indique, est un pointeur sur une fonction.

Par exemple, int (* ptrFunc) ();

Ici, ptrFunc est un pointeur vers une fonction qui ne prend aucun argument et retourne un entier. N'OUBLIEZ PAS de mettre entre parenthèses, sinon le compilateur supposera que ptrFunc est un nom de fonction normal, qui ne prend rien et renvoie un pointeur sur un entier.

Voici du code pour illustrer le pointeur de fonction.

#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;
}

Essayons maintenant de comprendre le concept de rappel en C en utilisant le pointeur de fonction.

Le programme complet a trois fichiers: callback.c, reg_callback.h et 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)();                               
}

Si nous exécutons ce programme, la sortie sera

Ceci est un programme démontrant la fonction de rappel à l'intérieur de register_callback à l'intérieur de my_callback à l'intérieur du programme principal

La fonction de couche supérieure appelle une fonction de couche inférieure comme un appel normal et le mécanisme de rappel permet à la fonction de couche inférieure d'appeler la fonction de couche supérieure via un pointeur vers une fonction de rappel.

Rappel en Java à l'aide de l'interface

Java n'a pas le concept de pointeur de fonction Il implémente le mécanisme de rappel via son mécanisme d'interface Ici, au lieu d'un pointeur de fonction, nous déclarons une interface ayant une méthode qui sera appelée lorsque l'appelé aura terminé sa tâche

Permettez-moi de le démontrer à travers un exemple:

L'interface de rappel

public interface Callback
{
    public void notify(Result result);
}

L'appelant ou la classe de niveau supérieur

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
}
}

La fonction Callee ou la couche inférieure

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
}
}

Rappel à l'aide du modèle EventListener

  • Élément de liste

Ce modèle est utilisé pour notifier de 0 à n nombres d'observateurs / auditeurs qu'une tâche particulière est terminée

  • Élément de liste

La différence entre le mécanisme de rappel et le mécanisme EventListener / Observer est que dans le rappel, l'appelé notifie l'appelant unique, tandis que dans Eventlisener / Observer, l'appelé peut notifier toute personne intéressée par cet événement (la notification peut aller à d'autres parties de la application qui n'a pas déclenché la tâche)

Permettez-moi de l'expliquer à travers un exemple.

L'interface d'événement

public interface Events {

public void clickEvent();
public void longClickEvent();
}

Widget de classe

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);
    }
}

Bouton de classe

public class Button extends Widget{
private String mButtonText;
public Button (){
} 
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}

Case à cocher Classe

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;
}
}

Classe d'activité

package 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();
    }   
}

Autre classe

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...");
}
}

Classe principale

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);
}
}

Comme vous pouvez le voir dans le code ci-dessus, nous avons une interface appelée événements qui répertorie essentiellement tous les événements qui peuvent se produire pour notre application. La classe Widget est la classe de base pour tous les composants de l'interface utilisateur tels que Button, Checkbox. Ces composants d'interface utilisateur sont les objets qui reçoivent réellement les événements du code d'infrastructure. La classe de widgets implémente l'interface d'événements et possède également deux interfaces imbriquées, à savoir OnClickEventListener et OnLongClickEventListener

Ces deux interfaces sont responsables de l'écoute des événements qui peuvent se produire sur les composants d'interface utilisateur dérivés du widget comme Button ou Checkbox. Donc, si nous comparons cet exemple avec l'exemple de rappel précédent à l'aide de l'interface Java, ces deux interfaces fonctionnent comme l'interface de rappel. Ainsi, le code de niveau supérieur (Here Activity) implémente ces deux interfaces. Et chaque fois qu'un événement se produit sur un widget, le code de niveau supérieur (ou la méthode de ces interfaces implémentées dans le code de niveau supérieur, qui est ici Activity) sera appelé.

Permettez-moi maintenant de discuter de la différence de base entre le modèle de rappel et le programme d'écoute d'événements. Comme nous l'avons mentionné, en utilisant le rappel, l'appelé ne peut informer qu'un seul appelant. Mais dans le cas du modèle EventListener, toute autre partie ou classe de l'application peut s'enregistrer pour les événements qui peuvent se produire sur le bouton ou la case à cocher. L'exemple de ce type de classe est l'AutreClasse. Si vous voyez le code de l'AutreClasse, vous constaterez qu'il s'est enregistré en tant qu'écouteur au ClickEvent qui peut se produire dans le Bouton défini dans l'Activité. La partie intéressante est que, outre l'activité (l'appelant), cette OtherClass sera également notifiée chaque fois que l'événement de clic se produit sur le bouton.


Veuillez éviter les liens contenant uniquement des réponses . Les réponses qui sont «à peine plus qu'un lien vers un site externe» peuvent être supprimées .
Quentin

3

Une fonction de rappel est une fonction que vous transmettez (comme référence ou pointeur) à une certaine fonction ou un certain objet. Cette fonction ou cet objet rappellera cette fonction à tout moment plus tard, éventuellement plusieurs fois, pour tout type de but:

  • notifier la fin d'une tâche
  • demande de comparaison entre deux éléments (comme dans c qsort ())
  • rendre compte de l'avancement d'un processus
  • notification des événements
  • déléguer l'instanciation d'un objet
  • déléguer la peinture d'une zone

...

Décrire un rappel comme une fonction appelée à la fin d'une autre fonction ou tâche est donc trop simplificateur (même s'il s'agit d'un cas d'utilisation courant).


2

Un rappel est une idée de passer une fonction en tant que paramètre à une autre fonction et de l'invoquer une fois le processus terminé.

Si vous obtenez le concept de rappel à travers les réponses impressionnantes ci-dessus, je vous recommande de connaître le contexte de son idée.

"Qu'est-ce qui les a incités (les informaticiens) à développer le rappel?" Vous pourriez apprendre un problème qui bloque (en particulier le blocage de l'interface utilisateur) et le rappel n'est pas la seule solution. Il existe de nombreuses autres solutions (ex: Thread, Futures, Promises ...).


1

Un domaine d'utilisation important est que vous enregistrez l'une de vos fonctions en tant que descripteur (c'est-à-dire un rappel), puis envoyez un message / appelez une fonction pour effectuer un travail ou un traitement. Maintenant, une fois le traitement terminé, la fonction appelée appelle notre fonction enregistrée (c'est-à-dire que le rappel est terminé), indiquant ainsi que le traitement est terminé.
Ce lien wikipedia explique assez bien graphiquement.


1

Une fonction de rappel, également connue sous le nom de fonction d'ordre supérieur, est une fonction qui est passée à une autre fonction en tant que paramètre, et la fonction de rappel est appelée (ou exécutée) à l'intérieur de la fonction parent.

$("#button_1").click(function() {
  alert("button 1 Clicked");
});

Ici, nous avons passé une fonction en tant que paramètre à la méthode click. Et la méthode click appellera (ou exécutera) la fonction de rappel que nous lui avons transmise.


2
Une fonction de rappel n'est pas elle-même une fonction d'ordre supérieur. Il est passé à une fonction d'ordre supérieur.
danio

1

Fonction de rappel Fonction qui est passée à une autre fonction comme argument.

function test_function(){       
 alert("Hello world");  
} 

setTimeout(test_function, 2000);

Remarque: Dans l'exemple ci-dessus, test_function utilisé comme argument pour la fonction setTimeout.


1
Bienvenue dans Stack Overflow! Avant de répondre à une question, lisez toujours les réponses existantes. Cette réponse a déjà été fournie. Au lieu de répéter la réponse, votez la réponse existante. Vous trouverez ici quelques directives pour rédiger de bonnes réponses .
dferenc
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.