Clôture (fonction) – Wikipedia

before-content-x4

Un Fermeture (ou Achèvement fonctionnel ) est un concept de la programmation fonctionnelle. Il décrit une fonction qui contient accès à votre contexte de création. Lors de l’appel, la fonction accède ensuite à ce contexte de création. Ce contexte (zone de mémoire, condition) ne peut pas être référencé en dehors de la fonction, c’est-à-dire H. invisible.

Une fermeture contient une référence à la fonction et à la partie du contexte de création qu’il utilise – la fonction et la structure de mémoire associée sont inextricablement terminées dans une référence (terme fermé). Il est comparable à un objet avec des attributs et des méthodes: il contient une identité, une condition et un comportement implicites.

Dans la syntaxe du langage de programmation, cela est souvent réalisé par deux fonctions imbriquées – la fonction principale interne est enfermée (terminée) d’une autre fonction. Cette fonction finale contient la structure de mémoire requise (voir les exemples ci-dessous). Il est construit de telle manière que lors de l’appel, il fournit une référence à la fonction interne avec les variables requises (la structure de mémoire). À proprement parler, la fermeture n’est pas la fonction intérieure seule, mais le regroupement de la fonction (intérieure) et de l’état de variable, sur lequel la référence montre.

Une fermeture peut également être considérée comme un objet qui n’a généralement qu’une seule méthode. Si la fermeture est générée avec d’autres fermetures au-dessus du même contexte, c’est un objet avec plusieurs méthodes. Les variables de la zone générée peuvent être utilisées par la fermeture comme attributs.

Les fermetures sont un concept qui provient des langages de programmation fonctionnelle, effectués dans LISP pour la première fois et a été entièrement pris en charge pour la première fois dans son schéma. En conséquence, il a également été pris en charge dans la plupart des langages de programmation fonctionnels ultérieurs (comme Haskell, OCAML).

Avec les fermetures, des zones modifiables non visibles mais contrôlées peuvent être créées, par exemple, le captage de données peut être réalisé ou mis en œuvre le curry.

La production d’une fermeture est associée à beaucoup moins de travail que la création d’une classe avec une seule méthode. Suivant la perspective orientée objet, les fermetures conviennent à la production rapide d’une structure semblable à un objet sans classe. La fonction anonyme est souvent utilisée comme méthode intérieure.

Dans un langage de programmation purement fonctionnel, une fermeture peut toujours être utilisée si elle est appelée en fonction ou doit entrer dans un appel de fonction en tant que paramètre. Dans ce dernier cas, il peut agir comme une fonction de rappel générée au terme et permet ainsi à un programme d’application de manipuler son propre flux de contrôle dans une mesure significative pendant son terme. Cependant, cela n’est généralement rendu possible que par un système de fermetures. En fait, le problème didactique est basé sur l’utilisation des fermetures.

Exemple de pseudocode [ Modifier | Modifier le texte source ]]

Dans l’exemple suivant, une fonction est d’abord fonction mère Sont définis. Cette fonction définit un nom de variable local gâteau et définit une fonction locale appelée fonction de l'enfant .

fonction Motherfunction { paramètre Kucht type = 'tarte aux pommes' fonction Fonction enfant { donner 'Je mange # {kuchtyp}'
    } donner fonction de l'enfant
} 
after-content-x4

Si vous appelez fonction mère La fonction locale fonction de l'enfant (pas leur résultat!). (Ceci est techniquement connu dans les langages de programmation non fonctionnels tels que C et les parents en tant que pointeur fonctionnel. Un pointeur fonctionnel tapé est appelé délégué.)

paramètre Meinkuchen = call_auf fonction mère 

La variable globale Meinkuchen Alors obtenez la fonction fonction de l'enfant attribué.

call_auf Meinkuchen 

Lorsque vous demandez Meinkuchen Par conséquent fonction de l'enfant réalisé. Bien qu’aucune variable globale gâteau existé, donne fonction de l'enfant La chaîne de caractères 'Je mange une tarte aux pommes' de parce qu’elle peut accéder à son contexte de création dans lequel la variable gâteau avec 'Gâteau aux pommes' est défini. C’est crucial: bien que fonction mère a déjà renvoyé une valeur – le contexte n’existe plus – peut fonction de l'enfant y accéder – fonction de l'enfant Il en va de même pour une fonction étroite.

[Édition:] Je mange une tarte aux pommes 

Avec un changement dans le code, la valeur des variables est maintenant Numéro_ gâteau dans le fonction mère Avec chaque accès à la fonction de fermeture augmente par un, qui peut être utilisé pour réaliser un compteur. La valeur dans Numéro_ gâteau est protégé de la manipulation et ne peut être que manger augmenter.

fonction Motherfunction { paramètre Numéro_ gâteau = 0 fonction Fonction enfant { paramètre Numéro_ Cake = Number_ Cake + 1 donner 'Je mange # {numéro_kuchen} gâteau'
    } donner fonction de l'enfant
} 

Avec plusieurs appels de la fonction mère à partir d’autres parties du programme, uniquement indirectement sur la valeur de la variable locale, qui n’est plus visible, ne peut être que indirectement visible sont accessibles et (uniquement) dans le fonction de l'enfant Les calculs (encapsulés) peuvent être effectués avec des valeurs autrement non échangeables – celles-ci sont montrées par les principaux avantages des fermetures mentionnées:

paramètre manger = call_auf fonction mère call_auf manger call_auf manger call_auf manger 
Je mange 1 gâteau
Je mange 2 gâteaux
Je mange 3 gâteaux 

Accès direct à la variable Numéro_ gâteau Est ainsi protégé, votre valeur peut (comme dans l’exemple) ou ne peut pas être servie directement à l’extérieur. En aucun cas, la valeur ne peut être modifiée par rapport à l’extérieur, si étroites -UP offrent plus de protection d’accès que, par exemple, en tant que champs «privés» d’une classe, par exemple en Java ou C #, ce qui est facile à éviter avec réflexion.

Comment interpréter cela dépend fortement de votre propre perspective sur les langages de programmation. Dans une perspective orientée objet, la fonction mère assume le rôle d’une classe, plus précisément un objet (l’instance d’une classe) et, d’un point de vue orienté objet, capsule ainsi les variables de l’enfant avec la fonction (s) de l’enfant en une seule unité.

En d’autres termes, une sorte de «mémoire» croisée est implémentée dans les fonctions, similaires à une variable statique, seulement plus puissante. Vu un peu différemment, cela peut également être considéré comme un changement dans le flux de contrôle, car l’exemple ci-dessus montre très bien. Les listes peuvent être implémentées en tant qu’appel fonctionnel, par exemple, car un résultat différent peut être livré à chaque fois que la “mémoire”) est appelée. C # utilise cela comme un cas spécial, par exemple lors de la mise en œuvre de “rendement de rendement”. L’élément suivant d’un type listable comme une liste, pour ainsi dire, “paresseux” (paresseux), c’est-à-dire H. Pour économiser des ressources uniquement si nécessaire. [d’abord]

after-content-x4

Exigences conceptuelles pour les fermetures dans les langages de programmation [ Modifier | Modifier le texte source ]]

La fermeture représente un modèle de programmation fonctionnelle comme mentionné, ils sont souvent difficiles à comprendre pour les programmeurs de programmation purement fonctionnelle, même s’ils sont de plus en plus implémentables.

Les «blocs de construction» conceptuels suivants sont nécessaires pour rendre une fermeture implémentable dans un langage de programmation.

1. Les fonctions doivent être autorisées comme des objets de retour d’une autre fonction, en utilisant au moins des éléments utilisés pour aider, tels que les mains fonctionnelles, les délégués ou les expressions lambda. On parle également de fonctions de première classe. (L’inverse est en particulier le cas si les fonctions ne peuvent être considérées et utilisées que comme une sorte de commande nommée).

2. Dans l’exemple ci-dessus, la fonction interne doit pouvoir accéder aux variables de la fonction externe (environnement d’appel). Contrairement aux variables locales, ces variables sont également appelées «variables libres» du point de vue de la fonction intérieure.

3. Le compilateur doit être en mesure de reconnaître que la valeur (condition) des variables en dehors de sa portée réelle (portée) est requise et en tenant activement en compte lors de la compilation. Techniquement, ces variables ne sont généralement plus stockées sur la pile, mais cela est résolu différemment, par ex. B. en générant réellement une classe (anonyme) et une instance qui contient les variables (membres) requises et la fonction interne (en tant que fonction membre).

Ce n’est que maintenant que tous les éléments constitutifs sont ensemble à une définition raccourcie mais plus technique du terme Fermeture À installer, à proprement parler par des fermetures lexicales au sens plus étroit:

Les fermetures sont donc une technique de programmation ou des structures pour implémenter le skoping lexical (portée anglaise) avec des variables libres dans les langues avec des fonctions de première classe.

Fermetures dynamiques et lexicales [ Modifier | Modifier le texte source ]]

La première implémentation des fermetures résulte du type de mise en œuvre des environnements d’exécution dans LISP. Dans les premières implémentations LISP, il n’y avait pas de skop lexical de la lexicale. L’environnement d’exécution d’une instruction consistait en une soi-disant liste avec des obligations variables qui pourraient être atteintes via une seule référence. Une fermeture sur une fonction consistait alors en un couple composé de la définition de la fonction et de la référence à la liste A valide à la période de définition de la fermeture. Ce couple généré par la fonction LISP est une fermeture dynamique avec le nom historique Funarg (argument fonctionnel). Si le Funarg est venu plus tard à l’exécution, cela s’est produit dans le contexte de la liste A apportée avec eux plutôt que dans le contexte de la liste A actuellement valide. [2]

La portée lexicale aujourd’hui utilisée dans LISP comme dans toutes les autres langues conduit à une fermeture lexicale, qui est également fonctionnelle dans les langues compilées. Il ne résulte que par l’intervention active par le compilateur en identifiant les références de la fonction sur les variables qui sont libres et en dehors de celui-ci et génèrent du code, qui compose ces liaisons avec la fonction ensemble lors du retour de son contexte de définition. Cela se produit avant cette fonction – maintenant en tant que fermeture – est mise à la disposition de l’appelant. Étant donné que cette liaison des variables n’est plus liée lexicalement, elle ne peut pas rester sur la pile, mais est placée sur le tas par le système de temps d’exécution. Avec une formation simultanée de plusieurs fermetures au-dessus de la même liaison variable, le système de temps d’exécution garantit que la même copie basée sur un tas de cette liaison variable est utilisée dans les deux fermetures.

Il existe également des langages de programmation non fonctionnels qui prennent en charge cette fonction. Cela inclut Ada, [3] C ++ (AB C ++ 11), C #, Go, Groovy, Java, [4] Javascript, [5] Lua, objet Pascal (Delphi), [6] [7] PHP, Perl, Python, Ruby, Smalltalk, Swift et Visual Basic .NET. Apple a élargi le CCG et a été le plus de fermetures, les littéraux des blocs de blocs pour C et ont proposé cela pour la normalisation. [8]

Lisp commun [ Modifier | Modifier le texte source ]]

Cet exemple utilise une fermeture pour activer une élégante requête de base de données. La fermeture provient de la fonction nom est livré. À travers le fonction spéciale lambda Une fonction sans nom est créée dans laquelle la valeur du champ nom sur l’égalité avec une chaîne de caractères n est vérifié. L’appel (Le nom est "Elke") Fournissez donc une fermeture en tant que connexion à partir de la fonction anonyme et de la liaison variable de n À la chaîne de personnage “Elke”. Cela peut vérifier un enregistrement de données pour le même nom avec “Elke”. La fermeture peut directement à la fonction filtre sont remis, qui l’utilisent ensuite et renvoie le résultat.

( defparamètre  * dbase *  ' (( "Chaque"  "1,1,1980" )  ( "Nuit"  "2.3.1981" )  ( "Heidi"  "4.5.1982" )  ( "Nuit"  "5.6.1983" )  ( "Uschi"  "7.8.1984" )))  ( défunier  rendez-vous  ( enregistrer )  ( d'abord  enregistrer ))  ( défunier  nom est  ( nom )  ( lambda  ( enregistrer )  ( égal  ( rendez-vous  enregistrer )  nom )))  ( défunier  filtre  ( prédicat  liste )  ( supprimer si-non  prédicat  liste ))  

Ces définitions rendent désormais possible la requête élégante suivante:

( imprimer  ( filtre  ( nom est  "Nuit" )  * dbase * ))  

Il doit être compris comme suit: l’appel de la fonction (nom-est "gabi") offre une fermeture. C’est une connexion à partir du code de comparaison ici (Nom de l'enregistrement d'égal (Get-Name)) de la fonction nom est et la liaison de la chaîne de caractères "Nuit" une variable de matrice nom . C’est sémantiquement la requête (Egal (Get-Name Record) "Gabi") . Cette comparaison est la fonction de fermeture filtre remettre cette comparaison. L’exécution de ce filtrage conduit alors au résultat:

(( "Nuit"  "2.3.1981" )  ( "Nuit"  "5.6.1983" ))  

Perler [ Modifier | Modifier le texte source ]]

Le contexte de tout fragment de code est déterminé, entre autres, par les symboles disponibles:

# pragma  utiliser  strict ;  sous  fonction  {  # Copier les arguments en variables nommées  mon  ( $ var1 ,  $ Var2 )  =  @_ ;  Code de blocs #  }  

Dans l’exemple indiqué ci-dessus sont les variables $ var1 et $ Var2 Valide et visible à chaque point. Lorsque vous quittez la fonction, vous serez bien rangé avec le bloc abandonné (“allez” hors de portée ) et sont alors inconnus. Tout accès supplémentaire serait une erreur.

Fermetures Offrez maintenant la possibilité d’élargir la zone de validité de ces variables au-delà de sa fin officielle. À cette fin, une fonction est simplement définie dans la portée qui utilise les variables pertinentes:

# pragma  utiliser  strict ;  sous  fonction  {  mon  ( $ var1 ,  $ Var2 )  =  @_ ;  retour  sous  {  imprimer  "Dont: $ was1, $ var2.n"  };  }  mon  $ f  =  fonction ( "Bonjour" ,  8 ));  mon  $ g  =  fonction ( "bar" ,  "ET" ));  # Appel de $ f  $ f -> ();  # Appel de $ g  $ g -> ();  

Le système de temps d’exécution fournit maintenant lors de la sortie de la fonction fonction a déclaré que les références aux variables de bloc $ var1 et $ Var2 Existant – La valeur de retour est un sous-programme anonyme, qui à son tour contient des références aux variables de bloc. $ var1 et $ Var2 Par conséquent, restez avec leurs valeurs actuelles. Parce que la fonction préserve les variables de cette manière, elle devient une fermeture.

En d’autres termes, même après avoir quitté la zone de validité réelle des variables, vous pouvez appeler à tout moment $ f -> () Et l’appel $ g -> () Exécuter et sera toujours affiché comme les valeurs des variables valides lors de la définition des fonctions.

Il en résulte la sortie:

Dont: Hallo, 8.
Qui: Bar, Y. 

Vous ne pouvez plus modifier ces valeurs car les variables en dehors de la fermeture ne sont plus disponibles. Cependant, cela est principalement dû à la définition de la fonction: bien sûr, la fermeture aurait non seulement pu dépenser les valeurs, mais aussi modifier ou même rendre le code d’appel à nouveau disponible par référence. Dans la variante suivante, par exemple, les fonctions d’incrément et de décrément sont introduites:

# pragma  utiliser  strict ;  # fonction  sous  fonction  {  mon  ( $ var1 ,  $ Var2 )  =  @_ ;  retour  (  sous  { imprimer  "Dont: $ was1, $ var2.n" },  sous  { $ var1 ++ ;  $ Var2 ++ ;},  sous  { $ var1 - ;  $ Var2 - ;}  ));  }  # Appelez la fonction  mon  ( $ imprimante ,  $ incrément ,  $ décrémentor )  =  fonction ( 3 , 5 ));  # Utiliser les fermetures  $ imprimante -> ();  $ incrément -> ();  $ imprimante -> ();  $ incrément -> ();  $ incrément -> ();  $ imprimante -> ();  

Il en résulte la sortie:

Dont: 3, 5.
Dont: 4, 6.
Dont: 6, 8. 

Les fermetures peuvent donc être utilisées, par exemple, pour chavirer l’accès à des données sensibles.

Python [ Modifier | Modifier le texte source ]]

Suivant un exemple simple de compteur dans Python, qui ne nécessite pas de conteneur (nommé) qui stocke l’état du compteur actuel.

def  fermeture ():  récipient  =  [ 0 ]]  def  Inc ():  récipient [ 0 ]]  + =  d'abord  def  obtenir ():  retour  récipient [ 0 ]]  retour  Inc ,  obtenir  

Dans l’exemple, dans le fermeture -Function a créé deux objets fonctionnels, tous deux de la liste récipient Reportez-vous à leur portée globale. Est le fermeture Donc-fonction traitée (après un appel) et les deux objets de fonction retournés sont en outre référencés, puis le récipient -List on, même si la portée de la fermeture a déjà été laissée. De cette façon, la liste est conservée dans une portée anonyme. Vous ne pouvez pas aller directement à la liste récipient accès. Devenir les deux objets fonctionnels Inc et obtenir Le conteneur disparaît également.

La fermeture de l’exemple précédent est ensuite utilisée de la manière suivante:

>>> i, g = fermeture ()
>>> g ()
0
>>> i ()
>>> i ()
>>> g ()
2 

Ocaml [ Modifier | Modifier le texte source ]]

OCAML le permet dans ce qui suit:

laisser  comptoir ,  Inc ,  réinitialiser  =  laisser  n  =  référence  0  dans  ( fonction  ()  ->  ! n ),  (* comptoir  *)  ( fonction  ()  ->  n : =  ! n  +  d'abord ),  (* incrément *)  ( fonction  ()  ->  n : = 0  )  (* réinitialiser  *)  

Maintenant, le compteur peut être utilisé comme suit:

#  comptoir () ;;  (* Résultats 0 *)  #  Inc () ;;  #  comptoir () ;;  (* Résultats 1 *)  #  Inc () ; Inc () ; Inc () ;;  #  comptoir () ;;  (* Résultats 4 *)  #  réinitialiser () ;;  #  comptoir () ;;  (* Résultats 0 *)  #  n ;;  (* n est encapsulé *)  Non lié  valeur  n  

Au lieu d’un entier (“entier”), bien sûr, tous les objets ou variables de tous les types peuvent être encapsulés.

Javascrip [ Modifier | Modifier le texte source ]]

Dans la fonction F1, une autre fonction F2 est définie comme la fermeture;

laisser  F1  =  fonction ()  {  // Définissez une fonction externe F1 ...  laisser  valeur  =  22 ;  // ... et créer une pièce de nom dedans.  laisser  F2  =  fonction ()  {  // définir une fonction intérieure ...  retour  valeur ;  // ... qui étend la pièce de nom à l'extérieur.  }  retour  F2 ;  // retourne F2 par F1, qui devient une fermeture.  }  laisser  un  =  F1 ();  // a est la fonction de fermeture renvoyée par F1 (), ...  console . enregistrer ( F1 ());  // ... aussi: function () {return wert;}  console . enregistrer ( Type de  valeur ));  // n'est pas défini  console . enregistrer ( un ());  // Résultats 22  console . enregistrer ( F1 () ());  // Résultats 22, F2 () mais n'est pas disponible ici  

L’exemple ci-dessus se formule un peu différemment, la fonction intérieure est maintenant appelée directement:

laisser  F3  =  fonction ()  {  laisser  valeur  =  23 ;  // La fonction F3 renvoie la fonction de fermeture!  retour  fonction ()  {  retour  valeur ;  };  }  laisser  b  =  F3 ();  // b est à nouveau la fonction renvoyée par f3 () ...  console . enregistrer ( b ());  // ... et livre maintenant 23  console . enregistrer ( b ));  // b reste un appel de fonction!  console . enregistrer ( F3 () ());  // délivre également 23  

La fonction intégrée sert de fournisseur de la valeur définie dans la fonction globale.

La fonction globale peut également être définie comme une fonction anonyme:

laisser  valeur  =  24 ;  laisser  c  =  ( fonction ()  {  // l'extérieur en fonction anonyme et ...  retour  valeur ;  // ... définissez la fonction intérieure dedans.  } ());  // la fonction maintenant avec (); Appeler.  console . enregistrer ( c ));  // Résultats 24  

La fermeture peut également être créée avec une fonction de constructeur:

laisser  d  =  ( nouveau  Fonction ( "Retour de valeur;" )) ();  // définir et appeler avec un constructeur  

Deux [ Modifier | Modifier le texte source ]]

Lua a un -in construit et, dans le sens de la programmation, également un support intuitif pour les fermetures, dont l’implémentation est similaire à celle de Python:

fonction  additionneur ( X )  - Générateur de fonctions  retour  fonction ( et )  - Anonyme, pour ajouter une fonction privée  retour  X + et  - x vient ici du contexte extérieur  fin  fin  

Une utilisation d’échantillons ressemblerait à ceci:

ajouter  =  additionneur ( 2 )  - Ici, la fermeture est générée  imprimer ( ajouter ( dix ))  -> Numéro 12  imprimer ( ajouter ( - 2 ))  -> Problème 0  

Une mise en œuvre de fermeture dans Lua est en [9] décrit.

Erlang [ Modifier | Modifier le texte source ]]

Erlang en tant que langage fonctionnel a également des fermetures, qui, cependant, Amusant (Singulier Amusant , depuis fonction ) d’être nommé.

faire quelque chose ( Amusant )  ->  Amusant ( 4 ).  principal ()  ->   Était  =  37 ,   F  =  amusant ( N )  ->  Était  +  N  fin .   Résultat  =  faire quelque chose ( F ).   % Résultat =: = 41 =: = 37 + 4  

C # [ Modifier | Modifier le texte source ]]

C # prend en charge les fermetures sous forme de délégués. [dix]

privé  statique  Action  Création ()  {   // Déclaration d'une variable dans le contexte local   était  X  =  0 ;   // Création d'un délégué de fermeture à l'aide d'une expression de lambda   Action  fermeture  =  ()  =>  Console . Écrit ( X ));   // Changement dans le contexte local   X  =  d'abord ;   // Retour de la fermeture au contexte primordial   retour  fermeture ;  }  static void Main()
{
    var closure = CreateClosure();

    // Im globalen Kontext
    // Variable x wird nur noch innerhalb der Closure referenziert

    // Führe Closure aus; Schreibt "1" auf die Konsole
    closure();
}

C ++ 14 [ Modifier | Modifier le texte source ]]

C ++ prend en charge les fermetures en utilisant des expressions lambda [11] (De C ++ 11), qui peut être des capsules dans des objets fonctionnels, donc-calé radio, la fonction type std ::.

#inclure   #inclure   #inclure   MST :: fonction < annuler ( annuler ) >  create_closure ()  {   MST :: chaîne  gâteau ( "Gâteau aux pommes" ));   // Les variables locales sont transférées à l'objet fonctionnel ici comme copie   retour  [ = ] ()  {  MST :: couter  <<  "Je mange "  <<  gâteau  <<  MST :: fin ;  };  }  int main() {
    std::function<void(void)> closure = create_closure();
    closure();

    return 0;
}

Avec l’aide du mot clé mutable Une véritable fermeture peut être créée à partir d’une fonction lambda, qui a non seulement ses propres variables, mais peut également les modifier (cependant, le “nombre de_cooks” variable dans le bloc extérieur n’est pas modifié, mais seulement une copie de celui-ci):

#inclure   #inclure   MST :: fonction < annuler ( annuler ) >  fonction mère ()  {   int  Numéro_ gâteau  =  0 ;   // La copie couverte de la variable peut également modifier votre valeur ici.   retour  [ = ] ()  mutable  {  MST :: couter  <<  "Je mange "  <<  ++ Numéro_ gâteau  <<  " Gâteau. n " ;  };  }  int  principal ()  {      std::function<void(void)> essen = mutterfunktion();

    essen();
    essen();
    essen();

    return 0;
}

Numéro de ce programme:

Je mange 1 gâteau.
Je mange 2 gâteaux.
Je mange 3 gâteaux. 

Java [ Modifier | Modifier le texte source ]]

En Java, les fermetures sont également possibles à partir de la version 8, avec certaines hypothèses spécifiques de langage à observer via des expressions de lambda. Par exemple, le code suivant ne se compilerait pas.

privé  statique  Fonction < Chaîne ,  Fournisseur < Chaîne >>  Générateur  =  nom de gâteau  ->  {  int  comptoir  =  0 ;  retour  ()  ->  "Je mange "  +  comptoir ++  +  ""  +  nom de gâteau ;  // Erreur: le compteur ne peut pas être modifié  };  public  statique  annuler  principal ( Chaîne []  args )  {  Fournisseur < Chaîne >  cheesecake  =  Générateur . appliquer ( "Cheesecake" ));  Système . dehors . println ( cheesecake . obtenir ());  Système . dehors . println ( cheesecake . obtenir ());  Système . dehors . println ( cheesecake . obtenir ());  }  

En Java, le code peut accéder aux variables de la méthode environnante dans une expression de lambda, mais ne peut pas la changer. Dans l’exemple ci-dessus, le code du fournisseur retourné essaie par Counter ++ Pour modifier la valeur d’une variable, qui déclenche une erreur de compilateur. Afin d’éviter cette restriction, les données modifiées doivent être encapsulées dans des objets, par exemple avec AtomicInteger:

privé  statique  Fonction < Chaîne ,  Fournisseur < Chaîne >>  Générateur  =  nom de gâteau  ->  {  Atomicinteger  comptoir  =  nouveau  Atomicinteger ( 0 ));  retour  ()  ->  "Je mange "  +  comptoir . Incordance Tand ()  +  ""  +  nom de gâteau ;  };  public  statique  annuler  principal ( Chaîne []  args )  {  Fournisseur < Chaîne >  cheesecake  =  Générateur . appliquer ( "Cheesecake" ));  Système . dehors . println ( cheesecake . obtenir ());  Système . dehors . println ( cheesecake . obtenir ());  Système . dehors . println ( cheesecake . obtenir ());  }  

Le code corrigé de cette manière compilé parce que la référence à l’objet du compteur dans l’expression de Lambda reste inchangée. La sortie est alors:

Je mange 0 cheesecake
Je mange 1 cheesecake
Je mange 2 cheesecake 

Php [ Modifier | Modifier le texte source ]]

PHP prend en charge les fermetures de la version 5.3.0 sous la forme de fonctions anonymes. [douzième]

Techniquement, PHP résout la mise en œuvre de cette fonctionnalité à travers sa propre classe de «fermeture». [13]

$ Fonction mère  =  fonction ()  {  $ numéro_ gâteau  =  0 ;  $ Fonction enfant  =  fonction ()  utiliser  ( & $ numéro_ gâteau )  {  $ numéro_ gâteau  =  $ numéro_ gâteau  +  d'abord ;  imprimer  "Je mange { $ numéro_ gâteau } Gâteau n " ;  };  retour  $ Fonction enfant ;  };  manger $  =  $ Fonction mère ();  manger $ ();  manger $ ();  manger $ ();  

La sortie des vues est la suivante:

Je mange 1 gâteau
Je mange 2 gâteaux
Je mange 3 gâteaux 

À partir de PHP 7.0, les fermetures sont également soutenues sous la forme de classes anonymes. [14]

manger $  =  nouveau  classe ()  {  privé  $ numéro_ gâteau  =  0 ;  public  fonction  __invoquer ()  {  $ ceci -> Numéro_ gâteau  =  $ ceci -> Numéro_ gâteau  +  d'abord ;  imprimer  "Je mange { $ ceci -> Numéro_ gâteau } Gâteau n " ;  }  };  manger $ ();  manger $ ();  manger $ ();  

Les deux implémentations fournissent des dépenses identiques.

Rouiller [ Modifier | Modifier le texte source ]]

Rust a déjà pris en charge les fermetures de la version 0.1, le retour des fermetures des fonctions jusqu’à la rouille 1.26 (publiée le 10 mai 2018) via un pointeur vers la mémoire du tas (via Boîte ) arriver.

FN  fonction mère ()  -> Boîte < homme  Fnmut ()  -> () >  {   laisser  mais  Numéro_ gâteau  =  0 ;   laisser  fonction de l'enfant  =  déplacer  ||  {   Numéro_ gâteau  + =  d'abord ;   println! ( "Je mange du gâteau" ,  Numéro_ gâteau ));   };   // [ex.1] Erreur si le gâteau numéro_ n'implémenterait pas la copie (voir ci-dessous)   // println! ("Maintenant le nombre de gâteaux: {}", gâteau numéro_);   retour  Boîte :: nouveau ( fonction de l'enfant ));  }

fn main() {
    let mut essen = mutterfunktion();
    essen();
    essen();
    essen();
}

Sortir:

Je mange 1 gâteau
Je mange 2 gâteaux
Je mange 3 gâteaux 

Dans Rust 1.26 le trait implorant Syntaxe se stabilise, qui le même code sans indirection via la mémoire du tas ( Box :: new () ) Active:

FN  fonction mère ()  -> implorant  Fnmut ()  -> ()  {   laisser  mais  Numéro_ gâteau  =  0 ;   déplacer  ||  {   Numéro_ gâteau  + =  d'abord ;   println! ( "Je mange du gâteau" ,  Numéro_ gâteau ));   }  }  fn main() {
    let mut essen = mutterfunktion();
    essen();
    essen();
    essen();
}

La valeur de retour de Fonction mère () le FN Trait, par lequel le type exact de la valeur de retour n’est déterminé que lorsque la fonction est utilisée.

La rouille se différencie entre les conversions fonctionnelles et les fermetures, ainsi que divers types fermés: FN , Fnmut et FnOnce . Un FN -Closure ne peut pas modifier le contexte dans lequel il est appelé. Un Fnmut -Closure ne peut modifier la variable dans le contexte mais a été marquée. Un FnOnce -Closure consomme la variable créée dans le contexte. Ici pourrait manger() Je viens d’être appelé exactement une fois – à la fin de la première fermeture, le destructeur est Numéro_ gâteau Et la variable n’est plus disponible.

Si [Ex.1] L’édition est commentée:

Est maintenant le nombre de gâteaux: 0
Je mange 1 gâteau
Je mange 2 gâteaux
Je mange 3 gâteaux 

Le déplacer Le mot-clé est utilisé pour posséder la variable Numéro_ gâteau afficher. Depuis notre variable Numéro_ gâteau peut être copié (variable du type U32 Mettre en œuvre le Copie -Trait), nous pouvons utiliser la variable au sein de la fonction mère une fois la valeur réelle de la fermeture. Voici Numéro_ gâteau Copié, d. H. Bien que nous ayons déjà défini le numéro sur 1 dans le code, la sortie dépense toujours 0 car il s’agit d’une copie complète de la variable. Est le type de Numéro_ gâteau Non copié, le compilateur passe une erreur.

Scala [ Modifier | Modifier le texte source ]]

Scala est un langage de programmation fonctionnel basé sur la machine virtuelle Java.

objet  Closurest  {  def  principal ( args :  Déployer [ Chaîne ])::  Unité  =  {  def  fonction de l'enfant  =  fonction mère  println ( "Appeler Kinder" )  fonction de l'enfant ;  fonction de l'enfant ;  fonction de l'enfant ;  }  était  Numéro_ gâteau  =  0 ;  def  fonction mère  :  Unité  =  {  était  Kuchtype  =  "Gâteau aux pommes"  def  fonction de l'enfant  :  Unité  =  {  Numéro_ gâteau  =  Numéro_ gâteau  +  d'abord  retour  Système . dehors . println ( "Je mange "  +  Numéro_ gâteau . tostring ()  +  ""  +  Kuchtype )  }  fonction de l'enfant  }  }  

Voici la variable Numéro_ gâteau uniquement modifiables entre les appels s’il était défini dans un contexte global (également dans une autre classe ou un autre objet). La sortie du programme est:

Appeler les enfants
Je mange 1 tarte aux pommes
Je mange 2 tartes aux pommes
Je mange 3 tartes aux pommes 
  • Ralf H. Güting, Martin Erwig, Traducteur . Springs, 1999, ISBN 3-540-65389-9
  • Damian Conway, Perl orienté objet
  • Oliver Lau, Andreas Linke, Torsten T. Will: Variable à faire – Certes dans les langages de programmation actuels. Dans: c’est , 17/2013, S. 168ff.
  1. Ted Neward: État basé sur la fermeture: C #. 2. avril 2016, consulté le 14 avril 2022 (Anglais).
  2. John McCarthy u. un.: Manuel des programmeurs LISP 1.5 . (PDF; 4,5 Mo) Software Preservation.org; Consulté le 12 mars 2014.
  3. John Barnes: Justification de l’ADA 2005
  4. Fermetures en java
  5. Fermetures en javascript (Anglais)
  6. Craig Stuntz: Comprendre les méthodes anonymes. Dans: Community.embarcadero.com. 4. août 2008, consulté le 14 avril 2022 (Anglais).
  7. Barry Kelly: Tiburon: Fun avec des génériques et des méthodes anonymes .
  8. N1370: Extensions d’Apple à C (PDF; 69 Ko)
  9. La mise en œuvre de Lua 5.0
  10. Dustin Campbell: Qu’y a-t-il dans une fermeture. (Pas plus disponible en ligne.) 9 février 2007, archivé à partir de Original suis 15. août 2014 ; Consulté le 12 avril 2014 (Anglais).
  11. Fonctions Lambda. Récupéré le 17 octobre 2015 (Anglais).
  12. Fonctions anonymes. Consulté le 19 mai 2015 .
  13. La classe de fermeture. Consulté le 19 mai 2015 .
  14. Joe Watkin, Phil Sturgeon: Classes anonymes. 22. septembre 2013, Consulté le 19 mai 2015 (Anglais).
after-content-x4