web-dev-qa-db-fra.com

Qu'est-ce qu'un descripteur de fonction et comment est-il utile?

Quelqu'un peut-il m'expliquer la signification du @ (fonction handle) et pourquoi l'utiliser?

38
Dikla

opérateur de poignée de fonction dans MATLAB agit essentiellement comme un pointeur vers une instance spécifique d'une fonction. Certaines des autres réponses ont discuté de quelques-unes de ses utilisations, mais j'ajouterai ici une autre utilisation que j'ai souvent pour cela: le maintien de l'accès à des fonctions qui ne sont plus "à portée".

Par exemple, la fonction suivante initialise une valeur count, puis renvoie un descripteur de fonction à une fonction imbriquée increment:

function fHandle = start_counting(count)

  disp(count);
  fHandle = @increment;

  function increment
    count = count+1;
    disp(count);
  end

end

Puisque la fonction increment est un fonction imbriquée , elle ne peut être utilisée que dans la fonction start_counting (c'est-à-dire l'espace de travail de start_counting est sa "portée"). Cependant, en renvoyant un descripteur à la fonction increment, je peux toujours l'utiliser en dehors de start_counting, et il conserve toujours l'accès aux variables dans l'espace de travail de start_counting! Cela me permet de faire ceci:

>> fh = start_counting(3);  % Initialize count to 3 and return handle
     3

>> fh();  % Invoke increment function using its handle
     4

>> fh();
     5

Remarquez comment nous pouvons continuer à incrémenter le nombre même si nous sommes en dehors de la fonction start_counting. Mais vous pouvez faire quelque chose d'encore plus intéressant en appelant start_counting à nouveau avec un numéro différent et en stockant le handle de fonction dans une autre variable:

>> fh2 = start_counting(-4);
    -4

>> fh2();
    -3

>> fh2();
    -2

>> fh();  % Invoke the first handle to increment
     6

>> fh2();  % Invoke the second handle to increment
    -1

Notez que ces deux compteurs différents fonctionnent indépendamment. La fonction gère fh et fh2 pointe vers différentes instances de la fonction increment avec différents espaces de travail contenant des valeurs uniques pour count.

En plus de ce qui précède, l'utilisation de descripteurs de fonction en conjonction avec des fonctions imbriquées peut également aider à rationaliser la conception de l'interface graphique, comme je l'illustre dans cet autre SO post .

49
gnovice

Les poignées de fonction sont un outil extrêmement puissant dans matlab. Un bon début est de lire l'aide en ligne, qui vous en donnera bien plus que moi. À l'invite de commandes, tapez

doc function_handle

Un descripteur de fonction est un moyen simple de créer une fonction sur une seule ligne. Par exemple, supposons que je souhaite intégrer numériquement la fonction sin (k * x), où k a une valeur externe fixe. Je pourrais utiliser une fonction en ligne, mais une poignée de fonction est beaucoup plus nette. Définir une fonction

k = 2;
fofx = @(x) sin(x*k);

Voyez que je peux maintenant évaluer la fonction fofx sur la ligne de commande. MATLAB sait ce qu'est k, nous pouvons donc utiliser fofx comme fonction maintenant.

fofx(0.3)
ans =
         0.564642473395035

En fait, nous pouvons transmettre fofx, efficacement comme variable. Par exemple, permet d'appeler quad pour effectuer l'intégration numérique. Je choisirai l'intervalle [0, pi/2].

quad(fofx,0,pi/2)
ans =
         0.999999998199215

Comme vous pouvez le voir, quad a fait l'intégration numérique. (Soit dit en passant, une fonction en ligne aurait été au moins un ordre de magie plus lent et beaucoup moins facile à utiliser.)

x = linspace(0,pi,1000);
tic,y = fofx(x);toc
Elapsed time is 0.000493 seconds.

À titre de comparaison, essayez une fonction en ligne.

finline = inline('sin(x*k)','x','k');
tic,y = finline(x,2);toc
Elapsed time is 0.002546 seconds.

Une chose intéressante à propos d'une poignée de fonction est que vous pouvez la définir à la volée. Minimiser la fonction cos (x), sur l'intervalle [0,2 * pi]?

xmin = fminbnd(@(x) cos(x),0,2*pi)
xmin =
          3.14159265358979

Il existe de très nombreuses autres utilisations des descripteurs de fonction dans MATLAB. Je n'ai fait qu'effleurer la surface ici.

18
user85109

Avertissement: code non testé ...

L'opérateur de poignée de fonction vous permet de créer une référence à une fonction et de la transmettre comme n'importe quelle autre variable:

% function to add two numbers
function total = add(first, second) 
    total = first + second;
end

% this variable now points to the add function
operation = @add;

Une fois que vous avez un descripteur de fonction, vous pouvez l'invoquer comme une fonction régulière:

operation(10, 20); % returns 30

Une bonne chose à propos des poignées de fonction est que vous pouvez les transmettre comme n'importe quelle autre donnée, vous pouvez donc écrire des fonctions qui agissent sur d'autres fonctions. Cela vous permet souvent de séparer facilement la logique métier:

% prints hello
function sayHello 
    disp('hello world!');
end

% does something five times
function doFiveTimes(thingToDo) 
    for idx = 1 : 5 
        thingToDo();
    end
end

% now I can say hello five times easily:
doFiveTimes(@sayHello);

% if there's something else I want to do five times, I don't have to write
% the five times logic again, only the operation itself:
function sayCheese 
    disp('Cheese');
end
doFiveTimes(@sayCheese);

% I don't even need to explicitly declare a function - this is an 
% anonymous function:
doFiveTimes(@() disp('do something else'));

Le documentation Matlab a une description plus complète de la syntaxe Matlab, et décrit quelques autres utilisations pour les descripteurs de fonctions comme les rappels graphiques.

15
Dan Vinton