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

Les fonctions de rappel sonnent plus impressionnantes que les fonctions ordinaires rien que par leur nom. Alors, qu'est-ce qu'une fonction de rappel exactement ? Pardonnez-moi de ne pas avoir lu beaucoup de livres ; je n'ai jamais vu de définition des fonctions de rappel dans un livre. J'ai cherché sur Baidu et j'ai trouvé une grande variété d'opinions. Une grande partie utilise un scénario comme celui-ci pour expliquer : la personne A se rend au magasin de la personne B pour acheter quelque chose, mais il s'avère que c'est en rupture de stock. La personne A laisse son numéro à la personne B, et la personne B prévient la personne A lorsqu'il est en stock. Cela fait davantage penser à des opérations asynchrones qu'à des fonctions de rappel. Il y a aussi deux phrases anglaises qui m'ont profondément marqué : 1) If you call me, I will call you back ; 2) Don't call me, I will call you. Elles semblent avoir du sens, mais après réflexion, les fonctions ordinaires ne peuvent-elles pas aussi accomplir ces deux points ? Donc je pense que ces affirmations ne sont pas tout à fait appropriées, parce qu'elles n'expriment pas les caractéristiques des fonctions de rappel, c'est-à-dire qu'elles ne montrent pas la différence entre elles et les fonctions ordinaires. Cependant, je pense que l'explication de Baidu Baike est plutôt bonne (bien que je me plaigne souvent de Baidu Search...) : une fonction de rappel est une fonction appelée via un pointeur de fonction. Si vous passez le pointeur (adresse) d'une fonction comme paramètre à une autre fonction, et que lorsque ce pointeur est utilisé pour appeler la fonction vers laquelle il pointe, on dit qu'il s'agit d'une fonction de rappel.

Laissez-moi d'abord partager mon point de vue. Nous pouvons décomposer le terme littéralement. Pour « callback function » (fonction de rappel), en chinois, cela peut en fait être compris de deux manières : 1) la fonction qui est rappelée ; 2) la fonction qui se retourne pour effectuer l'action d'appel. Alors qu'est-ce que diable que ce « se retourner pour appeler » ?

Tout d'abord, examinons l'analyse des callbacks par Wikipédia: En programmation informatique, un callback est tout code exécutable transmis comme argument à un autre code, qui est censé rappeler (exécuter) l'argument à un moment donné. Cette exécution peut être immédiate, comme dans un callback synchrone, ou survenir plus tard, comme dans un callback asynchrone. Autrement dit, transmettre du code exécutable à un autre code comme paramètre, et ce code sera appelé et exécuté à un moment donné, c'est ce qu'on appelle un callback. Si le code est exécuté immédiatement, on parle de callback synchrone ; s'il est exécuté plus tard, on parle de callback asynchrone. Nous ne discuterons pas ici du synchrone et de l'asynchrone ; veuillez vous référer aux ressources pertinentes.

Voyons maintenant une déclaration concise et claire d'un expert sur Stack Overflow :Un « callback » est toute fonction qui est appelée par une autre fonction, laquelle prend la première fonction comme paramètre. Autrement dit, lorsque la fonction F1 appelle la fonction F2, la fonction F1 transmet le pointeur d'une autre fonction F3 à la fonction F2 comme paramètre. Pendant l'exécution de la fonction F2, la fonction F2 appelle la fonction F3. Cette action est appelée un callback, et la fonction F3 qui a d'abord été passée comme pointeur puis rappelée plus tard est la fonction de rappel. À présent, vous devriez comprendre la définition d'une fonction de rappel, n'est-ce pas ?

2. Pourquoi utiliser des fonctions de rappel ?

Beaucoup de personnes pourraient se demander pourquoi ne pas simplement écrire le nom de la fonction directement à l'endroit du rappel, comme pour les appels de fonction ordinaires ? Cela ne fonctionnerait-il pas aussi ? Pourquoi devons-nous utiliser des fonctions de rappel ? C'est une bonne réflexion, car de nombreux exemples expliquant les fonctions de rappel que l'on trouve en ligne peuvent en réalité être entièrement implémentés avec des appels de fonction ordinaires. Pour répondre à cette question, commençons par comprendre les avantages et le but des fonctions de rappel, à savoir le découplage. Oui, la réponse est aussi simple que cela. C'est précisément en raison de cette caractéristique que les fonctions ordinaires ne peuvent pas remplacer les fonctions de rappel. Donc, à mes yeux, c'est la plus grande particularité des fonctions de rappel. Regardons une image sur Wikipédia que je trouve très bien dessinée.

Voici un extrait incomplet de code C pour illustrer la signification du diagramme ci-dessus :

Exemple

#include<stdio.h>
#include<softwareLib.h> // Inclure le fichier d'en-tête de la bibliothèque Software où réside la fonction de bibliothèque

int Callback() // Fonction de rappel
{
    // À FAIRE
    return 0;
}
int main() // Programme principal
{
    // À FAIRE
    Library(Callback);
    // À FAIRE
    return 0;
}

À première vue, un rappel semble n'être qu'un appel entre fonctions, pas différent des appels de fonctions ordinaires. Mais en y regardant de plus près, on peut trouver une différence clé : dans un rappel, le programme principal passe la fonction de rappel dans la fonction de bibliothèque comme un paramètre. De cette façon, tant que nous modifions les paramètres passés à la fonction de bibliothèque, nous pouvons implémenter différentes fonctionnalités. Cela ne semble-t-il pas très flexible ? Et il n'est pas du tout nécessaire de modifier l'implémentation de la fonction de bibliothèque. C'est le découplage. Regardez plus attentivement : la fonction principale et la fonction de rappel sont sur la même couche, tandis que la fonction de bibliothèque est sur une autre couche. Réfléchissez : si la fonction de bibliothèque ne nous est pas visible, nous ne pouvons pas modifier l'implémentation de la fonction de bibliothèque, ce qui signifie que nous ne pouvons pas faire en sorte que la fonction de bibliothèque appelle des fonctions ordinaires en modifiant la fonction de bibliothèque. Nous pouvons alors y parvenir uniquement en passant différentes fonctions de rappel. C'est aussi une situation courante dans le travail quotidien. Maintenant, si nous ramenons main(), Library() et Callback() aux fonctions F1, F2 et F3 précédentes, n'est-ce pas plus clair ?

Maintenant que vous comprenez les caractéristiques des fonctions de rappel, pouvez-vous déterminer approximativement quand elles doivent être utilisées ? C'est exact, vous pouvez utiliser des fonctions de rappel à de nombreux endroits pour remplacer des appels de fonctions ordinaires, mais à mon avis, les fonctions de rappel doivent être utilisées lorsque vous devez réduire le couplage.

3. Comment utiliser les fonctions de rappel ?

Maintenant que vous savez ce qu'est une fonction de rappel et que vous comprenez ses caractéristiques, comment devez-vous utiliser les fonctions de rappel ? Examinons ci-dessous un code simple et exécutable de fonction de rappel synchrone.

Exemple

#include<stdio.h>

int Callback_1() // Fonction de rappel 1
{
    printf("Bonjour, ceci est Callback_1 ");
    return 0;
}

int Callback_2() // Fonction de rappel 2
{
    printf("Bonjour, ceci est Callback_2 ");
    return 0;
}

int Callback_3() // Fonction de rappel 3
{
    printf("Bonjour, ceci est Callback_3 ");
    return 0;
}

int Handle(int (*Callback)())
{
    printf("Entrée dans la fonction Handle. ");
    Rappel();
    printf("Sortie de la fonction Handle. ");
}

int main()
{
    printf("Entrée dans la fonction main. ");
    Handle(Callback_1);
    Handle(Callback_2);
    Handle(Callback_3);
    printf("Sortie de la fonction main. ");
    return 0;
}

Sortie :

Entering Main Function.
Entering Handle Function.
Hello, this is Callback_1
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_2
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_3
Leaving Handle Function.
Leaving Main Function.

Comme vous pouvez le voir, le paramètre de la fonction Handle() est un pointeur. Lors de l'appel de la fonction Handle() dans la fonction main(), les noms de fonctions Callback_1()/Callback_2()/Callback_3() lui sont passés. À ce stade, le nom de fonction est le pointeur vers la fonction correspondante. Autrement dit, une fonction de rappel est en réalité une utilisation de pointeurs de fonction. Relisez maintenant cette phrase : Un "callback" est toute fonction appelée par une autre fonction qui prend la première fonction comme paramètre. N'est-ce pas plus clair maintenant ?

4. Comment utiliser les fonctions de rappel avec des paramètres ?

Les plus observateurs auront peut-être remarqué que les fonctions de rappel dans les exemples précédents n'ont pas de paramètres. Alors, pouvons-nous appeler des fonctions de rappel qui ont des paramètres ? La réponse est oui. Comment les appeler alors ? Nous pouvons simplement modifier un peu l'exemple ci-dessus :

Exemple

#include<stdio.h>

int Callback_1(int x) // Fonction de rappel 1
{
    printf("Bonjour, ceci est Callback_1 : x = %d ", x);
    return 0;
}

int Callback_2(int x) // Fonction de rappel 2
{
    printf("Bonjour, ceci est Callback_2: x = %d ", x);
    return 0;
}

int Callback_3(int x) // Fonction de rappel 3
{
    printf("Bonjour, ceci est Callback_3: x = %d ", x);
    return 0;
}

int Handle(int y, int (*Callback)(int))
{
    printf("Entrée dans la fonction Handle. ");
    Rappel(y);
    printf("Sortie de la fonction Handle. ");
}

int main()
{
    int a = 2;
    int b = 4;
    int c = 6;
    printf("Entrée dans la fonction main. ");
    Handle(a, Callback_1);
    Handle(b, Callback_2);
    Handle(c, Callback_3);
    printf("Sortie de la fonction main. ");
    return 0;
}

Sortie :

Entering Main Function.
Entering Handle Function.
Hello, this is Callback_1: x = 2
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_2: x = 4
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_3: x = 6
Leaving Handle Function.
Leaving Main Function.

Comme vous pouvez le voir, il n'est pas aussi simple de changer directement int Handle(int (*Callback)()) en int Handle(int (*Callback)(int)). À la place, vous devez ajouter un paramètre supplémentaire pour stocker la valeur du paramètre de la fonction de rappel, comme le paramètre y dans int Handle(int y, int (*Callback)(int)) ici. De même, les fonctions de rappel avec plusieurs paramètres peuvent être utilisées.

URL de l'article original : https://www.cnblogs.com/jiangzhaowei/p/9129105.html