www.wikidata.de-de.nina.az
Eine Closure ist ein Konzept aus der funktionalen Programmierung Wenn eine Funktion die freie Variablen verwendet den Scope verlasst in dem diese vereinbart sind meistens weil sie selbst von einer Funktion zuruckgegeben wird und wird dieser Scope abgeraumt so waren diese freien Variablen ab diesem Zeitpunkt undefiniert Um dem zu begegnen setzt der Compiler bei der Ruckgabe eine neue Struktur zusammen Sie besteht aus dieser Funktion und samtlichen von ihr verwendeten freien Variablen Diese Struktur heisst Closure Der Name deutet an dass die betroffenen Variablenbindungen ab diesem Zeitpunkt nicht mehr von ausserhalb der Closure erreicht werden konnen Es gibt Ausnahmen falls mehrere Closures gleichzeitig erzeugt werden s u Die Closure wird von Laufzeitsystem und Compiler von reinen Funktionen unterschieden Sie muss auch logisch von diesen unterschieden werden da sie durch die in ihr enthaltenen auch ge closure ten Variablenbindungen innere Zustande hat und darum in aufeinanderfolgenden Aufrufen unterschiedliche Werte fur gleiche Argumente liefern kann Daher kann man eine Closure auch als Objekt ansehen das in der Regel nur eine Methode hat Wird die Closure zusammen mit weiteren Closures in demselben Kontext erzeugt so handelt es sich um ein Objekt mit mehreren Methoden Die in der Closure eingeschlossenen Variablen aus dem erzeugenden Bereich konnen von der Closure als Attribute verwendet werden Inhaltsverzeichnis 1 Herkunft 2 Vorteile und Eigenschaften 2 1 Beispiel in Pseudocode 3 Konzeptionelle Voraussetzungen fur Closures in Programmiersprachen 3 1 Dynamische und lexikalische Closures 4 Implementierungen 5 Beispiele von Implementierungen 5 1 Common Lisp 5 2 Perl 5 3 Python 5 4 OCaml 5 5 JavaScript 5 6 Lua 5 7 Erlang 5 8 C 5 9 C 5 10 Java 5 11 PHP 5 12 Rust 5 13 Scala 6 Literatur 7 Weblinks 8 EinzelnachweiseHerkunft BearbeitenClosures sind ein Konzept das aus den funktionalen Programmiersprachen stammt zum ersten Mal in Lisp auftrat und in seinem Dialekt Scheme erstmals vollstandig unterstutzt wurde Daraufhin wurde es auch in den meisten spateren funktionalen Programmiersprachen etwa Haskell Ocaml unterstutzt Vorteile und Eigenschaften BearbeitenMit Closures konnen nicht sichtbare aber kontrolliert veranderbare Bereiche erstellt werden beispielsweise kann damit Datenkapselung realisiert oder Currying umgesetzt werden Die Erzeugung einer Closure ist mit deutlich weniger Arbeit verbunden als die Erstellung einer Klasse mit nur einer Methode Objektorientierter Sichtweise folgend eignen sich Closures so zur schnellen Erzeugung einer objektahnlichen Struktur ohne eine Klasse Oftmals wird als innere Methode eine anonyme Funktion verwendet In einer rein funktionalen Programmiersprache kann eine Closure immer dann verwendet werden wenn sie entweder selbst als Funktion aufgerufen oder als Parameter in einen Funktionsaufruf eingehen soll Im letzteren Fall kann sie als zur Laufzeit erzeugte Call Back Funktion agieren und ermoglicht so einem Anwendungsprogramm in erheblichen Mass wahrend seiner Laufzeit den eigenen Kontrollfluss zu manipulieren Dies wird allerdings meistens erst durch ein System von Closures praktisch sinnvoll ermoglicht Auf dieser Tatsache beruht das didaktische Problem unerfahrenen Programmierern die Anwendung von Closures nahezubringen Beispiel in Pseudocode Bearbeiten Im folgenden Beispiel wird zunachst eine Funktion mutterfunktion definiert Diese Funktion setzt eine lokale Variable namens kuchentyp und definiert eine lokale Funktion namens kindfunktion funktion mutterfunktion setze kuchentyp Apfelkuchen funktion kindfunktion gib aus Ich esse kuchentyp gib zuruck kindfunktion Bei einem Aufruf gibt mutterfunktion die lokale Funktion kindfunktion nicht deren Ergebnis zuruck Dies ist in nicht funktionalen Programmiersprachen wie C und Verwandten technisch auch als Funktionszeiger bekannt Ein typisierter Funktionszeiger heisst Delegate setze meinkuchen rufe auf mutterfunktion Die globale Variable meinkuchen bekommt also die Funktion kindfunktion zugewiesen rufe auf meinkuchen Beim anschliessenden Aufruf von meinkuchen wird folglich kindfunktion ausgefuhrt Obwohl keine globale Variable kuchentyp existiert gibt kindfunktion die Zeichenkette Ich esse Apfelkuchen aus weil sie auf ihren Erstellungskontext zugreifen kann in dem die Variable kuchentyp mit Apfelkuchen definiert ist Entscheidend ist dabei Obwohl mutterfunktion schon einen Wert zuruckgegeben hat der Kontext also eigentlich nicht mehr existiert kann kindfunktion darauf zugreifen kindfunktion ist also eine Closure Funktion Ausgabe Ich esse Apfelkuchen Mit einer Anderung im Code wird nun der Wert der Variablen anzahl kuchen in der mutterfunktion mit jedem Zugriff auf die Closure Funktion um eins erhoht womit sich ein Zahler realisieren lasst Der Wert in anzahl kuchen ist vor Manipulation geschutzt und kann nur durch essen erhoht werden funktion mutterfunktion setze anzahl kuchen 0 funktion kindfunktion setze anzahl kuchen anzahl kuchen 1 gib aus Ich esse anzahl kuchen Kuchen gib zuruck kindfunktion Mit mehrfachen Aufrufen der Mutterfunktion von anderen Programmteilen aus kann nur indirekt auf den eigentlich nicht mehr sichtbaren Wert der lokalen Variable lt anzahl kuchen gt zugegriffen werden und nur innerhalb der kindfunktion konnen gekapselte Berechnungen mit sonst nicht veranderbaren Werten vorgenommen werden das zeigt die erwahnten Hauptvorteile von Closures setze essen rufe auf mutterfunktion rufe auf essen rufe auf essen rufe auf essen Ich esse 1 Kuchen Ich esse 2 Kuchen Ich esse 3 Kuchen Der direkte Zugriff auf die Variable anzahl kuchen ist so geschutzt ihr Wert kann wie im Beispiel oder konnte auch nicht direkt nach aussen gereicht werden Keinesfalls ist der Wert aber von aussen veranderbar damit bieten Closures mehr Zugriffsschutz als etwa als private deklarierte Felder einer Klasse etwa in Java oder C der etwa mit Reflection einfach zu umgehen ist Wie man dies interpretiert hangt stark von der eigenen Sichtweise auf Programmiersprachen ab Die Mutterfunktion ubernimmt aus objektorientierter Sichtweise die Rolle einer Klasse genauer eines Objekts der Instanz einer Klasse und kapselt aus objektorientierter Sicht so Kindvariablen mit Kindfunktion en zu einer Einheit Anders gesehen wird so eine Art aufrufubergreifendes Gedachtnis in den Funktionen implementiert ahnlich einer statischen Variablen nur leistungsfahiger Noch ein wenig anders betrachtet kann man dies auch als Veranderung des Kontrollfluss ansehen wie obiges Beispiel sehr gut zeigt Aufzahlungen konnen etwa als Funktionsaufruf implementiert werden da bei jedem Aufruf aufgrund des Gedachtnisses ein anderes Ergebnis geliefert werden kann C nutzt dies als Spezialfall etwa bei der Implementierung von yield return Dabei wird pro Aufruf Schritt fur Schritt das nachste Element eines aufzahlbaren Typs wie einer Liste sozusagen faul lazy d h ressourcensparend nur bei Bedarf zuruckzugeben 1 Konzeptionelle Voraussetzungen fur Closures in Programmiersprachen BearbeitenClosures stellen wie erwahnt ein Muster Funktionaler Programmierung dar sie sind fur Programmierer nicht rein funktionaler Programmiersprachen oftmals schwer zu verstehen auch wenn sie in zunehmend mehr Programmiersprachen umsetzbar sind Folgende konzeptionelle Bausteine sind notig um eine Closure in einer Programmiersprache umsetzbar zu machen 1 Funktionen mussen als Ruckgabeobjekte einer anderen Funktion erlaubt sein mindestens uber zu Hilfe genommene Elemente wie Funktionszeiger Delegates oder Lambda Ausdrucke Man spricht hier auch von First Class Funktionen Das Gegenteil ist insbesondere der Fall wenn Funktionen lediglich als eine Art benannter Befehl betrachtet und verwendet werden konnen 2 In obigem Beispiel muss die innere Funktion auf die Variablen der ausseren Funktion Aufrufumgebung zugreifen konnen Diese Variablen werden im Unterschied zu lokalen Variablen aus Sicht der inneren Funktion auch als freie Variablen englisch free variables bezeichnet 3 Der Compiler muss in der Lage sein zu erkennen dass der Wert Zustand der Variablen ausserhalb deren eigentlichen Gultigkeitsbereich scope benotigt wird und dies bei der Kompilierung aktiv berucksichtigen Technisch werden diese Variablen dann meist nicht mehr auf dem Stack abgelegt sondern dies wird anders gelost z B indem tatsachlich im Hintergrund eine anonyme Klasse samt Instanz erzeugt wird die die benotigten Member variablen und die innere Funktion als Memberfunktion enthalt Jetzt erst sind alle Bausteine beisammen um eine verkurzte aber technischere Definition des Begriffes Closure aufzustellen genau genommen von lexikalischen Closures im engeren Sinne Closures sind also eine Programmiertechnik bzw Strukturen um lexikalische Skopierung englisch scope mit freien Variablen in Sprachen mit First Class Funktionen umzusetzen Dynamische und lexikalische Closures Bearbeiten Die erste Implementierung von Closures ergab sich aus der Art der Implementierung von Ausfuhrungsumgebungen in Lisp In den ersten Lisp Implementierungen gab es keine lexikalische Skopierung Die Ausfuhrungsumgebung einer Anweisung bestand aus einer sogenannten A Liste mit Variablenbindungen die uber eine einzelne Referenz erreichbar war Eine Closure uber einer Funktion bestand dann aus einem Paar bestehend aus der Funktionsdefinition und der Referenz auf die zur Definitionszeit der Closure gultigen A Liste Dieses durch die Lisp Funktion FUNCTION erzeugte Paar ist eine dynamische Closure mit der historischen Bezeichnung FUNARG FUNctional ARGument Gelangte das FUNARG spater zur Ausfuhrung so geschah dies im Kontext der mitgebrachten A Liste anstatt im Kontext der aktuell gultigen A Liste 2 Die heute in Lisp wie in allen anderen Sprachen verwendete lexikalische Skopierung fuhrt zur lexikalischen Closure die auch in kompilierten Sprachen funktionsfahig ist Sie entsteht erst durch aktives Eingreifen des Compilers indem dieser die Bezuge der Funktion auf die innerhalb ihrer selbst freien und ausserhalb von ihr gebundenen Variablen identifiziert und Code erzeugt der diese Bindungen mit der Funktion zusammen bei ihrer Ruckgabe aus ihrem Definitionskontext zu einer Closure zusammensetzt Dies geschieht bevor diese Funktion nun als Closure dem Aufrufer zur Verfugung gestellt wird Da diese Variablenbindung nun nicht mehr lexikalisch gebunden ist kann sie nicht auf dem Stack verbleiben sondern wird vom Laufzeitsystem auf den Heap gelegt Bei gleichzeitiger Bildung mehrerer Closures uber derselben Variablenbindung sorgt das Laufzeitsystem dafur dass in beide Closures dieselbe Heap basierte Kopie dieser Variablenbindung eingesetzt wird Implementierungen BearbeitenEs existieren auch nicht funktionale Programmiersprachen die diese Funktion unterstutzen Dazu gehoren Ada 3 C ab C 11 C Go Groovy Java 4 JavaScript 5 Lua Object Pascal Delphi 6 7 PHP Perl Python Ruby Smalltalk Swift und Visual Basic NET Apple hat den gcc und Clang um Closures genannt Block Literals fur C erweitert und dies zur Standardisierung vorgeschlagen 8 Beispiele von Implementierungen BearbeitenCommon Lisp Bearbeiten Dieses Beispiel verwendet eine Closure um eine elegante Datenbankabfrage zu ermoglichen Die Closure wird von der Funktion name is geliefert Durch die special function lambda wird eine namenlose Funktion erzeugt innerhalb derer der Wert des Feldes name auf die Gleichheit mit einer Zeichenkette ngepruft wird Der Aufruf name is Elke liefert also eine Closure als Verbindung aus der anonymen Funktion und der Variablenbindung von n an die Zeichenkette Elke Diese kann einen Datensatz auf den Namensgleichheit mit Elke uberprufen Die Closure kann direkt an die Funktion filter ubergeben werden die diese dann anwendet und das Ergebnis zuruckgibt defparameter dbase Elke 1 1 1980 Gabi 2 3 1981 Heidi 4 5 1982 Gabi 5 6 1983 Uschi 7 8 1984 defun get name record first record defun name is name lambda record equal get name record name defun filter predicate list remove if not predicate list Diese Definitionen machen nun folgende elegante Abfrage moglich print filter name is Gabi dbase Sie ist folgendermassen zu verstehen Der Funktionsaufruf name is Gabi liefert eine Closure Sie ist hier eine Verbindung aus dem Vergleichscode equal get name record name aus der Funktion name is und der Bindung der Zeichenkette Gabi an die Variable name Damit handelt es sich semantisch um die Abfrage equal get name record Gabi Dieser Vergleich wird als Closure an die Funktion filter ubergeben die diesen Vergleich anwendet Ausfuhren dieser Filterung fuhrt dann zu dem Ergebnis Gabi 2 3 1981 Gabi 5 6 1983 Perl Bearbeiten Der Kontext eines beliebigen Code Fragments wird unter anderem durch die zur Verfugung stehenden Symbole bestimmt pragma use strict sub function Argumente in benannte Variablen kopieren my var1 var2 block code Im oben gezeigten Beispiel sind die Variablen var1 und var2 an jeder Stelle der Funktion gultig und sichtbar Beim Verlassen der Funktion werden sie zusammen mit dem verlassenen Block aufgeraumt gehen out of scope und sind anschliessend unbekannt Jeder weitere Zugriff ware ein Fehler Closures bieten nun die Moglichkeit den Gultigkeitsbereich solcher Variablen uber dessen offizielles Ende hinaus auszudehnen Dazu wird im Scope einfach eine Funktion definiert die die betreffenden Variablen verwendet pragma use strict sub function my var1 var2 return sub print Vars var1 var2 n my f function Hallo 8 my g function bar Y Aufruf von f f gt Aufruf von g g gt Das Laufzeitsystem stellt jetzt beim Verlassen der Funktion function fest dass noch Referenzen auf die Blockvariablen var1 und var2 bestehen der Ruckgabewert ist eine anonyme Subroutine die ihrerseits Verweise auf die Blockvariablen enthalt var1 und var2 bleiben deshalb mit ihren aktuellen Werten erhalten Weil die Funktion auf diese Weise die Variablen konserviert wird sie zur Closure Mit anderen Worten kann man auch nach dem Verlassen des eigentlichen Gultigkeitsbereichs der Variablen jederzeit den Aufruf f gt und den Aufruf g gt ausfuhren und wird im Ergebnis immer wieder die bei der Definition der Funktionen gultigen Werte der Variablen angezeigt bekommen Dies ergibt die Ausgabe Vars Hallo 8 Vars bar Y Andern kann man diese Werte nicht mehr da die Variablen ausserhalb der Closure nicht mehr verfugbar sind Das liegt aber vor allem an der Funktionsdefinition Naturlich hatte die Closure die Werte nicht nur ausgeben sondern auch bearbeiten oder auch aufrufendem Code wieder per Referenz zur Verfugung stellen konnen In der folgenden Variante werden beispielsweise Funktionen zum Inkrementieren und Dekrementieren eingefuhrt pragma use strict function sub function my var1 var2 return sub print Vars var1 var2 n sub var1 var2 sub var1 var2 call the function my printer incrementor decrementor function 3 5 use closures printer gt incrementor gt printer gt incrementor gt incrementor gt printer gt Dies ergibt die Ausgabe Vars 3 5 Vars 4 6 Vars 6 8 Closures lassen sich also beispielsweise dazu verwenden um den Zugriff auf sensible Daten zu kapseln Python Bearbeiten Folgend ein einfaches Beispiel fur einen Zahler in Python der ohne einen benannten Container auskommt der den aktuellen Zahlerstand speichert def closure container 0 def inc container 0 1 def get return container 0 return inc get Im Beispiel werden innerhalb der closure Funktion zwei Funktionsobjekte erstellt die beide die Liste container aus ihrem jeweils ubergeordneten Scope referenzieren Ist die closure Funktion also abgearbeitet nach einem Aufruf und werden die beiden zuruckgegebenen Funktionsobjekte weiter referenziert dann existiert die container Liste weiter obwohl der Closure Scope bereits verlassen wurde Auf diese Weise wird also die Liste in einem anonymen Scope konserviert Man kann nicht direkt auf die Liste container zugreifen Werden die beiden Funktionsobjekte inc und get nicht mehr referenziert verschwindet auch der Container Die Closure im vorigen Beispiel wird dann auf die folgende Weise verwendet gt gt gt i g closure gt gt gt g 0 gt gt gt i gt gt gt i gt gt gt g 2 OCaml Bearbeiten OCaml erlaubt das in folgender Weise let counter inc reset let n ref 0 in function gt n counter function gt n n 1 incrementor function gt n 0 reset jetzt ist der Zahler wie folgt anwendbar counter ergibt 0 inc counter ergibt 1 inc inc inc counter ergibt 4 reset counter ergibt 0 n n ist gekapselt Unbound value n Statt einer Ganzzahl Integer konnen naturlich auf diese Weise beliebige Objekte oder Variablen beliebiger Typen gekapselt werden JavaScript Bearbeiten In der Funktion f1 wird eine weitere Funktion f2 als Closure definiert let f1 function eine aussere Funktion f1 definieren let wert 22 und darin einen Namensraum erstellen let f2 function eine innere Funktion definieren return wert die den Namensraum nach aussen reicht return f2 f2 durch f1 zuruckgeben womit f2 zum closure wird let a f1 a ist die von f1 zuruckgegebene closure Funktion console log f1 also function return wert console log typeof wert ist undefined console log a ergibt 22 console log f1 ergibt 22 f2 ist hier aber nicht abrufbar Obiges Beispiel etwas anders formuliert die innere Funktion wird jetzt direkt aufgerufen let f3 function let wert 23 die Funktion f3 gibt gleich die closure Funktion zuruck return function return wert let b f3 b ist wieder die von f3 zuruckgegebene Funktion console log b und liefert jetzt als Ergebnis 23 console log b b bleibt aber weiterhin ein Funktionsaufruf console log f3 liefert ebenfalls 23 Die eingebettete Funktion dient jeweils als Lieferant des in der ubergeordneten Funktion definierten Wertes Die ubergeordnete Funktion kann auch als anonyme Funktion definiert werden let wert 24 let c function die aussere als anonyme Funktion und return wert darin die innere Funktion definieren die Funktion jetzt noch mit aufrufen console log c ergibt 24 Die Closure kann auch mit einer Konstruktorfunktion erzeugt werden let d new Function return wert mit einem Konstruktor definieren und aufrufen Lua Bearbeiten Lua hat eine eingebaute und im Sinne der Programmierung auch intuitiv nutzbare Unterstutzung fur Closures deren Implementierung ahnlich derjenigen in Python ist function adder x Funktionserzeuger return function y anonyme zu adder private Funktion return x y x stammt hier aus dem ausseren Kontext end end Eine Beispielnutzung sahe so aus add2 adder 2 hier wird die Closure erzeugt print add2 10 gt Ausgabe 12 print add2 2 gt Ausgabe 0 Eine Closure Implementierung in Lua ist in 9 beschrieben Erlang Bearbeiten Erlang als funktionale Sprache besitzt ebenfalls Closures die allerdings Funs Singular Fun von function genannt werden do something Fun gt Fun 4 main gt Var 37 F fun N gt Var N end Result do something F Result 41 37 4 C Bearbeiten C unterstutzt Closures in Form von Delegates 10 private static Action CreateClosure Deklaration einer Variablen im lokalen Kontext var x 0 Erstellung eines Closure Delegate mit Hilfe eines Lambda Ausdrucks Action closure gt Console WriteLine x Anderung am lokalen Kontext x 1 Ruckgabe der Closure in den ubergeordneten Kontext return closure static void Main var closure CreateClosure Im globalen Kontext Variable x wird nur noch innerhalb der Closure referenziert Fuhre Closure aus Schreibt 1 auf die Konsole closure C Bearbeiten C unterstutzt Closures mittels Lambda Ausdrucken 11 ab C 11 die sich in Funktionsobjekte sogenannte Funktoren des Typs std function kapseln lassen include lt string gt include lt iostream gt include lt functional gt std function lt void void gt create closure std string kuchen Apfelkuchen Lokale Variablen werden hier als Kopie in das Funktionsobjekt ubertragen return std cout lt lt Ich esse lt lt kuchen lt lt std endl int main std function lt void void gt closure create closure closure return 0 Mit Hilfe des Schlusselworts mutable kann aus einer Lambda Funktion eine echte Closure erstellt werden die nicht nur ihre eigenen Variablen besitzt sondern diese auch verandern kann die Variable anzahl kuchen im ausseren Block wird dabei jedoch nicht verandert sondern nur eine Kopie davon include lt iostream gt include lt functional gt std function lt void void gt mutterfunktion int anzahl kuchen 0 Die ubernommene Kopie der Variable kann hier zusatzlich ihren Wert verandern return mutable std cout lt lt Ich esse lt lt anzahl kuchen lt lt Kuchen n int main std function lt void void gt essen mutterfunktion essen essen essen return 0 Ausgabe dieses Programms Ich esse 1 Kuchen Ich esse 2 Kuchen Ich esse 3 Kuchen Java Bearbeiten In Java sind ab der Version 8 ebenfalls Closures moglich wobei dabei einige spezifische Annahmen der Sprache uber Lambda Ausdrucke zu beachten sind Der folgende Code wurde zum Beispiel nicht kompilieren private static Function lt String Supplier lt String gt gt generator kuchenname gt int zahler 0 return gt Ich esse zahler kuchenname Fehler zahler kann nicht geandert werden public static void main String args Supplier lt String gt kasekuchen generator apply Kasekuchen System out println kasekuchen get System out println kasekuchen get System out println kasekuchen get In Java kann der Code innerhalb eines Lambda Ausdrucks lesend auf die Variablen der umschliessenden Methode zugreifen kann sie jedoch nicht verandern Im obigen Beispiel versucht der Code des zuruckgegebenen Suppliers durch zahler den Wert einer Variable zu andern was einen Compilerfehler auslost Um diese Einschrankung zu umgehen mussen Daten die verandert werden in Objekten gekapselt werden zum Beispiel mit AtomicInteger private static Function lt String Supplier lt String gt gt generator kuchenname gt AtomicInteger zahler new AtomicInteger 0 return gt Ich esse zahler getAndIncrement kuchenname public static void main String args Supplier lt String gt kasekuchen generator apply Kasekuchen System out println kasekuchen get System out println kasekuchen get System out println kasekuchen get Der so korrigierte Code kompiliert da die Referenz auf das Zahlerobjekt im Lambda Ausdruck unverandert bleibt Die Ausgabe ist dann Ich esse 0 Kasekuchen Ich esse 1 Kasekuchen Ich esse 2 Kasekuchen PHP Bearbeiten PHP unterstutzt Closures ab Version 5 3 0 in Form anonymer Funktionen 12 Technisch lost PHP die Umsetzung dieser Funktionalitat durch eine eigene Closure Klasse 13 mutterfunktion function anzahl kuchen 0 kindfunktion function use amp anzahl kuchen anzahl kuchen anzahl kuchen 1 print Ich esse anzahl kuchen Kuchen n return kindfunktion essen mutterfunktion essen essen essen Die Ausgabe der Aufrufe lautet wie folgt Ich esse 1 Kuchen Ich esse 2 Kuchen Ich esse 3 Kuchen Ab PHP 7 0 werden Closures zusatzlich auch in Form anonymer Klassen unterstutzt 14 essen new class private anzahl kuchen 0 public function invoke this gt anzahl kuchen this gt anzahl kuchen 1 print Ich esse this gt anzahl kuchen Kuchen n essen essen essen Beide Implementierungen liefern identische Ausgaben Rust Bearbeiten Rust unterstutzte Closures bereits ab Version 0 1 die Ruckgabe von Closures aus Funktionen musste bis zu Rust 1 26 veroffentlicht am 10 Mai 2018 uber einen Zeiger auf den Heap Speicher via Box geschehen fn mutterfunktion gt Box lt dyn FnMut gt gt let mut anzahl kuchen 0 let kindfunktion move anzahl kuchen 1 println Ich esse Kuchen anzahl kuchen Ex 1 Fehler wenn anzahl kuchen nicht Copy implementieren wurde s u println Jetzt ist die Anzahl der Kuchen anzahl kuchen return Box new kindfunktion fn main let mut essen mutterfunktion essen essen essen Ausgabe Ich esse 1 Kuchen Ich esse 2 Kuchen Ich esse 3 Kuchen In Rust 1 26 wurde die impl Trait Syntax stabilisiert welche den gleichen Code ohne Indirektion via Heap Speicher Box new ermoglicht fn mutterfunktion gt impl FnMut gt let mut anzahl kuchen 0 move anzahl kuchen 1 println Ich esse Kuchen anzahl kuchen fn main let mut essen mutterfunktion essen essen essen Hierbei implementiert der Ruckgabewert von mutterfunktion den Fn trait wobei die Ermittlung des exakten Typs des Ruckgabewerts erst bei der Nutzung der Funktion erfolgt Rust differenziert hierbei zwischen Funktionszeigern und Closures sowie verschiedenen Closure Typen Fn FnMut und FnOnce Eine Fn Closure kann den Kontext in dem sie aufgerufen wird nicht modifizieren Eine FnMut Closure kann die Variable im Kontext nur modifizieren wenn diese als mut gekennzeichnet wurde Eine FnOnce Closure konsumiert die im Kontext erstellte Variable Hierbei konnte essen nur exakt einmal aufgerufen werden am Ende der ersten Closure lauft der Destruktor von anzahl kuchen und die Variable ist damit nicht mehr verfugbar Wenn Ex 1 auskommentiert wird ergibt die Ausgabe Jetzt ist die Anzahl der Kuchen 0 Ich esse 1 Kuchen Ich esse 2 Kuchen Ich esse 3 Kuchen Das move Schlusselwort wird gebraucht um den Besitz der Variable anzahl kuchen anzuzeigen Da unsere Variable anzahl kuchen kopierbar ist Variablen des Typs u32 implementieren den Copy Trait konnen wir die Variable innerhalb der Mutterfunktion noch verwenden nachdem der eigentliche Wert der Closure ubergeben wurde Hierbei wird anzahl kuchen kopiert d h obwohl wir im Code die Anzahl bereits auf 1 gesetzt haben gibt die Ausgabe noch 0 aus da es eine komplette Kopie der Variable ist Ist der Typ von anzahl kuchen nicht kopierbar gibt der Compiler einen Fehler aus Scala Bearbeiten Scala ist eine funktionale Programmiersprache auf Basis der Java Virtual Machine object ClosureTest def main args Array String Unit def kindfunktion mutterfunktion println Calling Kinder kindfunktion kindfunktion kindfunktion var anzahl kuchen 0 def mutterfunktion Unit var kuchentype Apfelkuchen def kindfunktion Unit anzahl kuchen anzahl kuchen 1 return System out println Ich esse anzahl kuchen toString kuchentype kindfunktion Hierbei ist die Variable anzahl kuchen uber Aufrufe hinweg nur veranderlich wenn sie in einem globalen Kontext durchaus auch in einer anderen Klasse oder einem anderen Objekt definiert wurde Die Ausgabe des Programms lautet Calling Kinder Ich esse 1 Apfelkuchen Ich esse 2 Apfelkuchen Ich esse 3 ApfelkuchenLiteratur BearbeitenRalf H Guting Martin Erwig Ubersetzerbau Springer 1999 ISBN 3 540 65389 9 Damian Conway Object Oriented Perl Oliver Lau Andreas Linke Torsten T Will Variablen to go Closures in aktuellen Programmiersprachen In c t 17 2013 S 168ff Weblinks BearbeitenWas ist eine Closure Einzelnachweise Bearbeiten Ted Neward Closure based State C 2 April 2016 abgerufen am 14 April 2022 englisch John McCarthy u a Lisp 1 5 Programmers Manual PDF 4 5 MB softwarepreservation org abgerufen am 12 Marz 2014 John Barnes Rationale for Ada 2005 Closures in Java Closures in JavaScript englisch Craig Stuntz Understanding Anonymous Methods In community embarcadero com 4 August 2008 abgerufen am 14 April 2022 englisch Barry Kelly Tiburon fun with generics and anonymous methods N1370 Apple s Extensions to C PDF 69 kB The implementation of Lua 5 0 Dustin Campbell What s In A Closure Nicht mehr online verfugbar 9 Februar 2007 archiviert vom Original am 15 August 2014 abgerufen am 12 April 2014 englisch Lambda functions Abgerufen am 17 Oktober 2015 englisch Anonymous functions Abgerufen am 19 Mai 2015 The Closure class Abgerufen am 19 Mai 2015 Joe Watkin Phil Sturgeon Anonymous Classes 22 September 2013 abgerufen am 19 Mai 2015 englisch Abgerufen von https de wikipedia org w index php title Closure Funktion amp oldid 236968180