Funktionsobjekt
Im Computerprogrammierung, a Funktionsobjekt[a] ist ein Konstrukt, das eine erlaubt Objekt aufgerufen oder genannt zu werden, als wäre es ein gewöhnlicher Funktionnormalerweise mit derselben Syntax (ein Funktionsparameter, der auch eine Funktion sein kann). Funktionsobjekte werden oft genannt Funkern.
Beschreibung
Eine typische Verwendung eines Funktionsobjekts ist schriftlich zurückrufen Funktionen. Ein Rückruf in prozedurale Sprachen, wie zum Beispiel C, kann durch Verwendung durchgeführt werden Funktionszeiger.[2] Es kann jedoch schwierig oder unangenehm sein, einen Zustand in oder aus der Rückruffunktion zu übergeben. Diese Einschränkung hemmt auch dynamischeres Verhalten der Funktion. Ein Funktionsobjekt löst diese Probleme, da die Funktion wirklich a ist Fassade für ein volles Objekt mit seinem eigenen Zustand.
Viele moderne (und einige ältere) Sprachen, z. C ++, Eiffel, Groovig, Lispeln, Smalltalk, Perl, Php, Python, Rubin, Scalaund viele andere, Unterstützung erstklassige Funktion Objekte und können sie sogar erheblich nutzen.[3] Funktionelle Programmierung Sprachen unterstützen zusätzlich Schließungen, d. H. Erstklassige Funktionen, die zur Erstellung von Zeiten Variablen in ihrer Umgebung "schließen" können. Während der Zusammenstellung eine Transformation als bekannt als Lambda Heben Umwandelt die Schließungen in Funktionsobjekte.
In C und C ++
Betrachten Sie das Beispiel einer Sortierroutine, bei der eine Rückruffunktion verwendet wird, um eine Bestellbeziehung zwischen zwei Elementen zu definieren. Das folgende C -Programm verwendet Funktionszeiger:
#enthalten / * QSORT () Rückruffunktion, gibt <0 bei a <b,> 0 zurück, wenn a> b, 0 wenn a == b */ int vergleiche(Const Leere* a, Const Leere* b) { Rückkehr ( *(int *)a - *(int *)b ); } ... // Prototyp von QSORT ist // void qsort (void *base, size_t nel, size_t width, int ( *vergleich) (const void *, const void *)); ... int hauptsächlich(Leere) { int Artikel[] = { 4, 3, 1, 2 }; QSORT(Artikel, Größe von(Artikel) / Größe von(Artikel[0]),, Größe von(Artikel[0]),, vergleiche); Rückkehr 0; }
In C ++ kann ein Funktionsobjekt anstelle einer gewöhnlichen Funktion verwendet werden, indem eine Klasse definiert wird, die Überlastungen das Funktionsaufrufoperator durch Definieren von Operator()
Mitgliedsfunktion. In C ++ kann dies wie folgt erscheinen:
// Comparator Predict: Gibt true zurück, wenn a <b, sonst falsch falsch Struktur Intcomparator { bool Operator() (Const int &a, Const int &b) Const { Rückkehr a < b; } }; int hauptsächlich() { std::Vektor<int> Artikel { 4, 3, 1, 2 }; std::Sortieren(Artikel.Start(),, Artikel.Ende(),, Intcomparator()); Rückkehr 0; }
Beachten Sie, dass die Syntax für die Bereitstellung des Rückrufs an die std :: sort ()
Die Funktion ist identisch, aber ein Objekt wird anstelle eines Funktionszeigers übergeben. Beim Aufrufen wird die Rückruffunktion genauso wie jede andere Mitgliedsfunktion ausgeführt und hat daher vollen Zugriff auf die anderen Mitglieder (Daten oder Funktionen) des Objekts. Dies ist natürlich nur ein triviales Beispiel. Um zu verstehen, welche Macht ein Functor mehr als eine reguläre Funktion bietet, berücksichtigen Sie den gemeinsamen Anwendungsfall von Sortieren von Objekten nach einem bestimmten Feld. Im folgenden Beispiel wird ein Functor verwendet, um eine einfache Mitarbeiterdatenbank nach der ID -Nummer jedes Mitarbeiters zu sortieren.
Struktur Vergleiche { Const std::Saite Sort_field; Vergleiche(Const std::Saite& sort_field="Name") : Sort_field(sort_field) { / * validieren sort_field */ } bool Operator() (Const Angestellter& a, Const Angestellter& b) { wenn (Sort_field == "Name") Rückkehr a.Name < b.Name; anders wenn (Sort_field == "das Alter") Rückkehr a.das Alter < b.das Alter; anders wenn (Sort_field == "idnum") Rückkehr a.idnum < b.idnum; anders / * Ausnahme oder so etwas */////// } }; int hauptsächlich() { std::Vektor<Angestellter> Emps; / * Code zur Füllung der Datenbank *// // Sortieren Sie die Datenbank nach Mitarbeiter -ID -Nummer std::Sortieren(Emps.Start(),, Emps.Ende(),, Vergleiche("idnum")); Rückkehr 0; }
Im C ++ 11Der Lambda -Ausdruck bietet eine prägnantere Möglichkeit, dasselbe zu tun.
int hauptsächlich() { std::Vektor<Angestellter> Emps; / * Code zur Füllung der Datenbank *// Const std::Saite sort_field = "idnum"; std::Sortieren(Emps.Start(),, Emps.Ende(),, [&sort_field] (Const Angestellter& a, Const Angestellter& b) { / * Code zum Auswählen und Vergleichen von Feld */ }); Rückkehr 0; }
Es ist möglich, Funktionsobjekte in anderen Situationen als als Rückruffunktionen zu verwenden. In diesem Fall der verkürzte Begriff Functor ist normalerweise nicht verwendet über das Funktionsobjekt. Fortsetzung des Beispiels,
Intcomparator CPM; bool Ergebnis = CPM(a, b);
Zusätzlich zu Klassentypfunktionen sind auch andere Arten von Funktionsobjekten in C ++ möglich. Sie können den Mitglieds-Zeiger von C ++ nutzen oder Schablone Einrichtungen. Die Ausdruckskraft von Vorlagen erlaubt einige Funktionelle Programmierung Zu verwendende Techniken, wie das Definieren von Funktionsobjekten in Bezug auf andere Funktionsobjekte (wie wie Funktionszusammensetzung). Ein Großteil des C ++ Standard -Vorlagenbibliothek (STL) nutzt die vorlagenbasierten Funktionsobjekte stark.
Staat aufrechterhalten
Ein weiterer Vorteil von Funktionsobjekten ist ihre Fähigkeit, einen Zustand aufrechtzuerhalten, der sich auswirkt Operator()
zwischen Anrufen. Zum Beispiel definiert der folgende Code a Generator Zählen Sie von 10 nach oben und wird elf Mal aufgerufen.
#enthalten #enthalten #enthalten Klasse Zähle von { Öffentlichkeit: Zähle von(int zählen) : zählen_(zählen) {} int Operator() ()) { Rückkehr zählen_++; } Privatgelände: int zählen_; }; int hauptsächlich() { Const int Zustand(10); std::generate_n(std::ostream_iterator<int>(std::Cout, "\n"), 11, Zähle von(Zustand)); }
In C ++ 14 oder später kann das obige Beispiel umgeschrieben werden wie:
#enthalten #enthalten #enthalten int hauptsächlich() { std::generate_n(std::ostream_iterator<int>(std::Cout, "\n"), 11, [zählen=10] () veränderlich { Rückkehr zählen++; }); }
In C#
Im C#, Funktionsobjekte werden durch deklariert Delegierte. Ein Delegierter kann mit einer benannten Methode oder a deklariert werden Lambda -Ausdruck. Hier ist ein Beispiel mit einer benannten Methode.
Verwendung System; Verwendung System.Collectionss.generic; Öffentlichkeit Klasse Vergleichklasse1 { Öffentlichkeit statisch int Vergleichefunktion(int x, int y) { Rückkehr x - y; } Öffentlichkeit statisch Leere Hauptsächlich() { var Artikel = Neu Aufführen<int> { 4, 3, 1, 2 }; Vergleich<int> del = Vergleichefunktion; Artikel.Sortieren(del); } }
Hier ist ein Beispiel mit einem Lambda -Ausdruck.
Verwendung System; Verwendung System.Collectionss.generic; Öffentlichkeit Klasse Vergleichsklasse2 { Öffentlichkeit statisch Leere Hauptsächlich() { var Artikel = Neu Aufführen<int> { 4, 3, 1, 2 }; Artikel.Sortieren((x, y) => x - y); } }
In d
D Bietet verschiedene Möglichkeiten, Funktionsobjekte zu deklarieren: Lisp/Python-Stil über via Schließungen oder c#-Style via Delegierte, beziehungsweise:
bool finden(T) (T[] Heuhaufen, bool delegieren(T) nadle_test) { für jeden (Stroh; Heuhaufen) { wenn (nadle_test(Stroh)) Rückkehr Stimmt; } Rückkehr FALSCH; } Leere hauptsächlich() { int[] Heuhaufen = [345, 15, 457, 9, 56, 123, 456]; int Nadel = 123; bool Nadetest(int n) { Rückkehr n == Nadel; } behaupten(finden(Heuhaufen, &Nadetest)); }
Der Unterschied zwischen a delegieren und ein Schließung in d wird automatisch und konservativ vom Compiler bestimmt. D unterstützt auch Funktionsliterale, die eine Definition im Lambda-Stil ermöglichen:
Leere hauptsächlich() { int[] Heuhaufen = [345, 15, 457, 9, 56, 123, 456]; int Nadel = 123; behaupten(finden(Heuhaufen, (int n) { Rückkehr n == Nadel; })); }
Damit der Compiler den Code (siehe oben) inzeilen kann, können Funktionsobjekte auch C ++-Stil über angegeben werden Bedienerüberlastung:
bool finden(T, F) (T[] Heuhaufen, F nadle_test) { für jeden (Stroh; Heuhaufen) { wenn (nadle_test(Stroh)) Rückkehr Stimmt; } Rückkehr FALSCH; } Leere hauptsächlich() { int[] Heuhaufen = [345, 15, 457, 9, 56, 123, 456]; int Nadel = 123; Klasse Nadetest { int Nadel; Dies(int n) { Nadel = n; } bool Opcall(int n) { Rückkehr n == Nadel; } } behaupten(finden(Heuhaufen, Neu Nadetest(Nadel))); }
In Eiffel
In dem Eiffel Softwareentwicklungsmethode und Sprache, Operationen und Objekte werden immer als separate Konzepte angesehen. Allerdings die Agent Der Mechanismus erleichtert die Modellierung von Operationen als Laufzeitobjekte. Agenten erfüllen den Anwendungsbereich, der Funktionsobjekten zugeschrieben wird, z. Die Gestaltung des Agentenmechanismus im Eiffel versucht, die objektorientierte Natur der Methode und Sprache widerzuspiegeln. Ein Agent ist ein Objekt, das im Allgemeinen eine direkte Instanz einer der beiden Bibliotheksklassen ist, die die beiden Arten von Routinen in Eiffel modellieren: VERFAHREN
und FUNKTION
. Diese beiden Klassen stammen aus dem abstrakteren Abstand ROUTINE
.
Innerhalb des Softwarentextes das Sprachschlüsselwort Agent
Ermöglicht die Konstruktion von Agenten in kompakter Form. Im folgenden Beispiel ist es das Ziel, die Aktion des Einschiebens der Anzeige in die Liste der Aktionen hinzuzufügen, die ausgeführt werden sollen, wenn eine Schaltfläche geklickt wird.
my_button.select_actions.erweitern (Agent my_gauge.Schritt vorwärts)
Die Routine erweitern
Referenziert im obigen Beispiel ist eine Funktion einer Klasse in einer GUI -Bibliothek (Graphical User Interface), die bereitgestellt werden soll ereignisgesteuerte Programmierung Fähigkeiten.
In anderen Bibliotheksklassen werden Agenten für verschiedene Zwecke verwendet. In einer Bibliothek, die Datenstrukturen unterstützt, z. B. eine Klassenmodellierung lineare Strukturen Effekte Universelle Quantifizierung mit einer Funktion für alle
of type Boolesche
das akzeptiert einen Agenten, eine Instanz von FUNKTION
als Argument. Also im folgenden Beispiel, my_action
wird nur ausgeführt, wenn alle Mitglieder von meine Liste
den Charakter enthalten '!':
meine Liste: Linked_list [Saite] ... wenn meine Liste.für alle (Agent {Saite}.hat ('!')) dann my_action Ende ...
Wenn Agenten erstellt werden, können die Argumente an die Routinen, auf die sie modellieren, und sogar das Zielobjekt, auf das sie angewendet werden abgeschlossen oder links offen. Geschlossene Argumente und Ziele erhalten Werte zur Erstellung von Agenten. Die Zuordnung von Werten für offene Argumente und Ziele wird bis zu einem bestimmten Zeitpunkt nach dem Erstellen des Agenten verschoben. Die Routine für alle
erwartet als Argument, ein Agent, der eine Funktion mit einem offenen Argument oder Ziel repräsentiert, das dem tatsächlichen generischen Parameter für die Struktur entspricht (Saite
In diesem Beispiel.)
Wenn das Ziel eines Agenten offen bleibt, wird der Klassenname des erwarteten Ziels, der in Zahnspangen eingeschlossen ist, durch eine Objektreferenz ersetzt, wie im Text gezeigt Agent {String} .has ('!')
Im obigen Beispiel. Wenn ein Argument offen bleibt, wird das Fragezeichencharakter ('?') Als Platzhalter für das offene Argument codiert.
Die Fähigkeit, offene Ziele und Argumente zu schließen oder zu hinterlassen, soll die Flexibilität des Agentenmechanismus verbessern. Betrachten Sie eine Klasse, die das folgende Verfahren enthält, um eine Zeichenfolge für die Standardausgabe nach einer neuen Zeile zu drucken:
print_on_new_line (s: Saite) - Drucken Sie `s ', der eine neue Linie vorangestellt ist tun drucken ("%N" + s) Ende
Das folgende Ausschnitt, von dem angenommen wird, dass er in derselben Klasse ist, verwendet, verwendet print_on_new_line
Um das Mischen offener Argumente und offener Ziele in Agenten zu demonstrieren, die als Argumente für dieselbe Routine verwendet werden.
meine Liste: Linked_list [Saite] ... meine Liste.alles machen (Agent print_on_new_line (?)) meine Liste.alles machen (Agent {Saite}.zu senken) meine Liste.alles machen (Agent print_on_new_line (?)) ...
Dieses Beispiel verwendet die Prozedur alles machen
Für lineare Strukturen, die die von einem Agenten für jedes Element in der Struktur modellierte Routine ausführen.
Die Abfolge von drei Anweisungen druckt die Zeichenfolgen in meine Liste
konvertiert die Saiten in Kleinbuchstaben und druckt sie dann erneut aus.
Verfahren alles machen
iteriert über die Struktur, die den Routine ausführt print_on_new_line
) oder das offene Ziel (im Fall des Agenten basierend auf zu senken
).
Offene und geschlossene Argumente und Ziele ermöglichen auch die Verwendung von Routinen, die mehr Argumente fordern, als dies erforderlich ist, indem alle außer der erforderlichen Anzahl von Argumenten geschlossen werden:
meine Liste.alles machen (Agent my_multi_arg_procedure (geschlossen_arg_1, ?, geschlossen_arg_2, geschlossen_arg_3)
Der Eiffel -Agentenmechanismus ist in der detailliert beschrieben Eiffel ISO/ECMA -Standarddokument.
In Java
Java hat kein erstklassige Funktionenso werden Funktionsobjekte normalerweise durch eine Schnittstelle mit einer einzelnen Methode ausgedrückt (am häufigsten der Abrufbar
Schnittstelle), typischerweise mit der Implementierung anonym innere Klasseoder, beginnend in Java 8, a Lambda.
Für ein Beispiel aus der Standardbibliothek von Java, java.util.collectionss.sort ())
nimmt ein Aufführen
und ein Functor, dessen Aufgabe es ist, Objekte in der Liste zu vergleichen. Ohne erstklassige Funktionen ist die Funktion Teil der Komparatorschnittstelle. Dies könnte wie folgt verwendet werden.
Aufführen<Saite> aufführen = Arrays.ASLIST("10", "1", "20", "11", "21", "12"); Vergleicher<Saite> NumstringComparator = Neu Vergleicher<Saite>() { Öffentlichkeit int vergleichen(Saite STR1, Saite STR2) { Rückkehr Ganze Zahl.Wert von(STR1).vergleichen mit(Ganze Zahl.Wert von(STR2)); } }; Sammlungen.Sortieren(aufführen, NumstringComparator);
In Java 8+ kann dies geschrieben werden als:
Aufführen<Saite> aufführen = Arrays.ASLIST("10", "1", "20", "11", "21", "12"); Vergleicher<Saite> NumstringComparator = (STR1, STR2) -> Ganze Zahl.Wert von(STR1).vergleichen mit(Ganze Zahl.Wert von(STR2)); Sammlungen.Sortieren(aufführen, NumstringComparator);
In JavaScript
Im JavaScript, Funktionen sind erstklassige Objekte. JavaScript unterstützt auch Schließungen.
Vergleichen Sie Folgendes mit dem nachfolgenden Python -Beispiel.
Funktion Akkumulator(Anfang) { var aktuell = Anfang; Rückkehr Funktion (x) { Rückkehr aktuell += x; }; }
Ein Beispiel dafür im Gebrauch:
var a = Akkumulator(4); var x = a(5); // x hat Wert 9 x = a(2); // x hat Wert 11 var b = Akkumulator(42); x = b(7); // x hat Wert 49 (Strom = 49 in Verschluss b) x = a(7); // x hat Wert 18 (Strom = 18 in Verschluss a)
In Julia
Im Julia, Methoden sind mit Typen verbunden. Daher ist es möglich, ein willkürliches Julia -Objekt "abrufbar" zu machen, indem Methoden zu seinem Typ hinzugefügt werden. (Solche "abrufbaren" Objekte werden manchmal als "Functors" bezeichnet.)
Ein Beispiel ist diese akkumulatorische strukturelle Struktur (basierend auf Paul Graham's Studie zur Programmiersprache Syntax und Klarheit):[4]
Julia> Veränderliche Struktur Akkumulator n::Int Ende Julia> Funktion (Acc::Akkumulator) (N2) Acc.n += N2 Ende Julia> a = Akkumulator(4) Akkumulator(4) Julia> a(5) 9 Julia> a(2) 11 Julia> b = Akkumulator(42) Akkumulator(42) Julia> b(7) 49
Ein solcher Akkumulator kann auch mit Schließung implementiert werden:
Julia> Funktion Akkumulator(N0) n = N0 Funktion(N2) n += N2 Ende Ende Akkumulator (generisch Funktion mit 1 Methode) Julia> a = Akkumulator(4) (::#1) (generische Funktion mit 1 Methode) Julia> a(5) 9 Julia> a(2) 11 Julia> b = Akkumulator(42) (::#1) (generische Funktion mit 1 Methode) Julia> b(7) 49
In Lisp und Schema
In lispen Familiensprachen wie z. Common Lisp, Planenund andere, Funktionen sind Objekte, genau wie Zeichenfolgen, Vektoren, Listen und Zahlen. Ein verschlusster Bediener schafft a Funktionsobjekt Aus einem Teil des Programms: Der Teil des Code, der als Argument für den Operator angegeben ist gefangen und im Funktionsobjekt gespeichert, das häufiger als a genannt wird Schließung. Die erfassten Bindungen spielen die Rolle von Mitgliedsvariablenund der Code -Teil der Schließung spielt die Rolle der Anonyme Mitgliedsfunktion, genau wie Operator () in C ++.
Der Schließkonstruktor hat die Syntax (Lambda (Parameter ...) Code ...)
. Das (Parameter ...)
Durch ein Teil kann eine Schnittstelle deklariert werden, so dass die Funktion die deklarierten Parameter nimmt. Das Code ...
Der Teil besteht aus Ausdrücken, die bewertet werden, wenn der Fondktor aufgerufen wird.
Viele Verwendungen von Funkern in Sprachen wie C ++ sind einfach Emulationen des fehlenden Schließkonstruktors. Da der Programmierer keinen Verschluss direkt konstruieren kann, muss er eine Klasse mit allen erforderlichen Zustandsvariablen und auch eine Mitgliedsfunktion definieren. Erstellen Sie stattdessen eine Instanz dieser Klasse und stellen Sie sicher, dass alle Mitgliedsvariablen durch ihren Konstruktor initialisiert werden. Die Werte werden genau aus den lokalen Variablen abgeleitet, die direkt durch einen Verschluss erfasst werden sollten.
Ein Funktionsobjekt unter Verwendung des Klassensystems, keine Verwendung von Schließungen:
(Defklasse Zähler () ((Wert : initarg :Wert : Accessor Wert von))) (Defmethod Functor-Call ((c Zähler)) (INCF (Wert von c))) (Defun Make-Counter (Ursprünglicher Wert) (maßgeschneidert 'Zähler :Wert Ursprünglicher Wert)) ;;;; Verwenden Sie den Zähler: (Defvar *c* (Make-Counter 10)) (Functor-Call *c*) -> 11 (Functor-Call *c*) -> 12
Da es keine Standardmethode gibt, um funktionierbare Objekte in LISP zu erstellen, fälschen wir sie, indem wir eine generische Funktion namens Functor-Call definieren. Dies kann für jede Klasse spezifisch sein. Die Standard -Funcall -Funktion ist nicht generisch; Es nimmt nur Funktionsobjekte an.
Es ist diese generische Funktion des Functor-Calls, die uns Funktionsobjekte gibt, die sind Ein Computerprogrammierkonstrukt, mit dem ein Objekt aufgerufen oder aufgerufen werden kann, als wäre es eine gewöhnliche Funktion, normalerweise mit derselben Syntax. Wir haben fast Die gleiche Syntax: Functor-Call anstelle von Funcall. Einige LISPs bieten Funktionbar Objekte als einfache Erweiterung. Objekte mit derselben Syntax wie Funktionen zu machen, ist ein ziemlich triviales Geschäft. Einen Funktionsanrufbetreiber mit verschiedenen Arten von arbeiten FunktionsfunktionenUnabhängig davon, ob sie Klassenobjekte oder Verschluss sind, ist nicht komplizierter als ein + -operator, der mit verschiedenen Arten von Zahlen funktioniert, wie z. B. Ganzzahlen, Realität oder komplexen Zahlen.
Nun, ein Zähler, der mit einem Verschluss implementiert ist. Dies ist viel kurzer und direkter. Das Ausgangswert der Make-Counter Fabrikfunktion wird direkt erfasst und verwendet. Es muss nicht über einen Konstruktor in ein Hilfsklassenobjekt kopiert werden. Es ist der Zähler. Es wird ein Hilfsobjekt erstellt, aber das passiert hinter den Kulissen.
(Defun Make-Counter (Wert) (Lambda () (INCF Wert))) ;;;; Verwenden Sie den Zähler (Defvar *c* (Make-Counter 10)) (Funcall *c*) ; -> 11 (Funcall *c*) ; -> 12
Das Schema erleichtert die Schließungen noch einfacher, und der Schema-Code verwendet tendenziell idiomatischere Programme höherer Ordnung.
(definieren (Make-Counter Wert) (Lambda () (einstellen! Wert (+ Wert 1)) Wert)) ;;;; Verwenden Sie den Zähler (definieren c (Make-Counter 10)) (c) ; -> 11 (c) ; -> 12
In derselben lexikalischen Umgebung kann mehr als ein Verschluss geschaffen werden. Ein Vektor von Schließungen, der jeweils eine bestimmte Art von Operation implementiert, kann ein Objekt mit einer Reihe von virtuellen Operationen sehr gut emulieren. Diese Art von einzelner Versand Objektorientierte Programmierung kann vollständig mit Schließungen durchgeführt werden.
So gibt es eine Art Tunnel, der von beiden Seiten des sprichwörtlichen Berges gegraben wird. Programmierer in OOP -Sprachen entdecken Funktionsobjekte, indem sie Objekte auf einen einschränken hauptsächlich Funktion zu tun Der funktionale Zweck dieses Objekts und sogar seinen Namen beseitigt, so dass es so aussieht, als würde das Objekt aufgerufen! Während Programmierer, die Verschluss verwenden einzelner Versand Typ OOP.
In objektiv-c
Im Ziel c, ein Funktionsobjekt kann aus dem erstellt werden Nsinvocation
Klasse. Die Konstruktion eines Funktionsobjekts erfordert eine Methodensignatur, das Zielobjekt und den Zielwahl. Hier ist ein Beispiel, um einen Aufruf zum aktuellen Objekt zu erstellen Mymethod
:
// ein Funktionsobjekt konstruieren Sel Sel = @Wähler(Mymethod); Nsinvocation* Inv = [Nsinvocation InvocationWithmethodsignatur: [selbst MethodicnatureForSelector:Sel]]; [Inv anvisieren:selbst]; [Inv SetSelector:Sel]; // die tatsächliche Aufruf durchführen [Inv aufrufen];
Ein Vorteil von Nsinvocation
ist, dass das Zielobjekt nach der Erstellung geändert werden kann. Ein einzelnes Nsinvocation
kann erstellt und dann für jede der beliebigen Anzahl von Zielen aufgerufen werden, beispielsweise von einem beobachtbaren Objekt. Ein Nsinvocation
kann nur aus einem Protokoll erstellt werden, aber es ist nicht einfach. Sehen hier.
In Perl
Im PerlEin Funktionsobjekt kann entweder aus dem Konstruktor einer Klasse erstellt werden, der eine Funktion zurückgibt, die über die Instanzdaten des Objekts geschlossen wurde, gesegnet in die Klasse:
Paket ACC1; Sub Neu { mein $ Klasse = Wechsel; mein $ arg = Wechsel; mein $ obj = Sub { mein $ num = Wechsel; $ arg += $ num; }; segnen $ obj, $ Klasse; } 1;
oder durch Überlastung der & {}
Bediener, damit das Objekt als Funktion verwendet werden kann:
Paket ACC2; verwenden Überlast '& {}' => Sub { mein $ sich selbst = Wechsel; Sub { mein $ num = Wechsel; $ sich selbst->{arg} += $ num; } }; Sub Neu { mein $ Klasse = Wechsel; mein $ arg = Wechsel; mein $ obj = { arg => $ arg }; segnen $ obj, $ Klasse; } 1;
In beiden Fällen kann das Funktionsobjekt entweder mit der Derercencing -Pfeilsyntax verwendet werden $ ref-> (@argumente):
verwenden ACC1; mein $ a = ACC1->Neu(42); drucken $ a->(10), "\n"; # Drucke 52 drucken $ a->(8), "\n"; # Drucke 60
oder verwenden die Coderef Dereferencing -Syntax & $ ref (@Arguments):
verwenden ACC2; mein $ a = ACC2->Neu(12); drucken &$ a(10), "\n"; # Drucke 22 drucken &$ a(8), "\n"; # Drucke 30
In PHP
Php 5.3+ hat erstklassige Funktionen Das kann verwendet werden, z. als Parameter für die usort () -Funktion:
$ a = Array(3, 1, 4); Usort($ a, Funktion ($ x, $ y) { Rückkehr $ x - $ y; });
Php 5.3+ unterstützt auch Lambda -Funktionen und Verschlüsse.
Funktion Akkumulator($ Start) { $ aktuell = $ Start; Rückkehr Funktion($ x) verwenden(&$ aktuell) { Rückkehr $ aktuell += $ x; }; }
Ein Beispiel dafür im Gebrauch:
$ a = Akkumulator(4); $ x = $ a(5); Echo "x = $ x
"; // x = 9 $ x = $ a(2); Echo "x = $ x
"; // x = 11
In PHP 5.3+ ist es auch möglich, Objekte durch Hinzufügen einer Magic __invoke () -Methode zu ihrer Klasse aufzurufen:[5]
Klasse Minus { Öffentlichkeit Funktion __aufrufen($ x, $ y) { Rückkehr $ x - $ y; } } $ a = Array(3, 1, 4); Usort($ a, Neu Minus());
In Powershell
In dem Windows PowerShell Sprache, ein Skriptblock ist eine Sammlung von Aussagen oder Ausdrücken, die als einzelne Einheit verwendet werden können. Ein Skriptblock kann Argumente akzeptieren und Werte zurückgeben. Ein Skriptblock ist eine Instanz eines Microsoft .NET Framework Typ System.Management.Automation.ScriptBlock.
Funktion Get-Akumulator($ x) { { Param($ y) Rückkehr $ x += $ y }.GetNewcLosure() }
PS C: \> $ a = Get-Akumulator 4 PS C: \> & $ a 5 9 PS C: \> & $ a 2 11 PS C: \> $ b = Get-Akumulator 32 PS C: \> & $ b 10 42
In Python
Im Python, Funktionen sind erstklassige Objekte, genau wie Zeichenfolgen, Zahlen, Listen usw. Diese Funktion beseitigt die Notwendigkeit, in vielen Fällen ein Funktionsobjekt zu schreiben. Jedes Objekt mit a __Anruf__()
Die Methode kann mithilfe der Funktions-Call-Syntax aufgerufen werden.
Ein Beispiel ist diese Akkumulatorklasse (basierend auf Paul Graham's Studie zur Programmiersprache Syntax und Klarheit):[6]
Klasse Akkumulator: def __drin__(selbst, n) -> Keiner: selbst.n = n def __Anruf__(selbst, x): selbst.n += x Rückkehr selbst.n
Ein Beispiel dafür, das verwendet wird (unter Verwendung des interaktiven Dolmetschers):
>>> a = Akkumulator(4) >>> a(5) 9 >>> a(2) 11 >>> b = Akkumulator(42) >>> b(7) 49
Da Funktionen Objekte sind, können sie auch lokal definiert werden, angegeben und von anderen Funktionen zurückgegeben werden. [7] Wie im folgenden Beispiel gezeigt:
def Akkumulator(n): def Inc.(x): nicht lokal n n += x Rückkehr n Rückkehr Inc.
In Ruby
Im RubinMehrere Objekte können als Funktionsobjekte betrachtet werden, insbesondere Methoden und Proc -Objekte. Ruby hat auch zwei Arten von Objekten, die als Halbfunktionsobjekte angesehen werden können: Ungemachtes Methode und Block. Unbeschwerte Methoden müssen zunächst an ein Objekt gebunden sein (so werden sie zu einer Methode), bevor sie als Funktionsobjekt verwendet werden können. Blöcke können als Funktionsobjekte bezeichnet werden, aber in jeder anderen Funktion als Objekt (z. B. als Argument bestanden) verwendet werden, müssen sie zunächst in einen Proc konvertiert werden. In jüngerer Zeit symbol :
) kann auch auf konvertiert werden zu Proc
s. Mit Ruby's Unary verwenden &
Bediener - Gleichwertig für Anrufe to_proc
auf einem Objekt und Angenommen, diese Methode gibt es- Das Ruby Extensions -Projekt Erstellt einen einfachen Hack.
Klasse Symbol def to_proc Proc { |obj, *Args| obj.senden(selbst, *Args) } Ende Ende
Jetzt Methode Foo
Kann ein Funktionsobjekt sein, d. H. a Proc
, via &: Foo
und verwendet über takes_a_functor (&:: foo)
. Symbol.to_proc
wurde am 11. Juni 2006 während Rubykaigi2006 offiziell zu Ruby hinzugefügt. [1]
Aufgrund der Vielfalt der Formen wird der Begriff Functor im Allgemeinen nicht in Ruby verwendet, um ein Funktionsobjekt zu bedeuten. Nur eine Art Versand Delegation eingeführt von der Rubin Facetten Das Projekt wird als Functor bezeichnet. Die grundlegendste Definition ist:
Klasse Functor def initialisieren(&Func) @func = Func Ende def method_ming(op, *Args, &blk) @func.Anruf(op, *Args, &blk) Ende Ende
Diese Verwendung ähnelt eher der von funktionalen Programmiersprachen verwendeten Sprachen wie Mlund die ursprüngliche mathematische Terminologie.
Andere Bedeutungen
In einem theoretischeren Kontext a Funktionsobjekt kann als ein Beispiel für die Klasse von Funktionen angesehen werden, insbesondere in Sprachen wie z. Common Lisp in welchen Funktionen sind erstklassige Objekte.
Das Ml Familie von Funktionelle Programmierung Sprachen verwendet den Begriff Functor eine darstellen a Kartierung Von Modulen bis hin zu Modulen oder von Typen bis zu Typen und ist eine Technik zum Wiederverwenden von Code. Auf diese Weise verwendete Funktionen sind analog zur ursprünglichen mathematischen Bedeutung von Functor in Kategoriestheorieoder zur Verwendung der generischen Programmierung in C ++, Java oder Ada.
Im Haskell, der Begriff Functor wird auch für ein Konzept verwendet, das mit der Bedeutung von bezogen wird Functor in der Kategorie -Theorie.
Im Prolog und verwandte Sprachen, Functor ist ein Synonym für Funktionssymbol.
Siehe auch
- Rückruf (Informatik)
- Verschluss (Informatik)
- Funktionszeiger
- Funktion höherer Ordnung
- Befehlsmuster
- Currying
Anmerkungen
Verweise
- ^ Was ist der Unterschied zwischen einem Funktionoiden und einem Funkartor?
- ^ Silan Liu. "C ++ Tutorial Teil I - Basic: 5.10 Funktionszeiger werden hauptsächlich zur Erreichung der Rückruftechnik verwendet, die gleich danach diskutiert wird.". Stativ: Programmier -Tutorials Copyright © Silan Liu 2002. Abgerufen 2012-09-07.
Funktionszeiger werden hauptsächlich verwendet, um eine Rückruftechnik zu erreichen, die gleich danach diskutiert wird.
- ^ Paweł Turlejski (2009-10-02). "C ++ Tutorial Teil I - Basic: 5.10 Funktionszeiger werden hauptsächlich zur Erreichung der Rückruftechnik verwendet, die gleich danach diskutiert wird.". Nur ein paar Zeilen. Abgerufen 2012-09-07.
PHP 5.3 führte zusammen mit vielen anderen Funktionen Verschlüsse ein. Jetzt können wir endlich all das coole Sachen machen, das Ruby / Groovy / Scala / Any_Moder_Language Jungs tun können, oder? Nun, wir können, aber wir werden es wahrscheinlich nicht ... hier ist der Grund.
- ^ Akkumulatorgenerator
- ^ PHP -Dokumentation zu magischen Methoden
- ^ Akkumulatorgenerator
- ^ Python -Referenzhandbuch - Funktionsdefinitionen
Weitere Lektüre
- David Vandevoorde & Nicolai M Josuttis (2006). C ++ - Vorlagen: Die vollständige Anleitung, ISBN0-201-73484-2: Insbesondere ist Kapitel 22 Funktionsobjekten gewidmet.
Externe Links
- Beschreibung aus dem Portland -Muster -Repository
- C ++ Erweiterte Designprobleme - Asynchron C ++ durch Kevlin Henney
- Die Funktionszeiger -Tutorials von Lars Haendel (2000/2001)
- Artikel "Verallgemeinerte Funktionszeiger" durch Kräuter Sutter
- Generische Algorithmen für Java
- PHP -Funktoren - Funktionsobjekte in PHP
- Was zum Teufel ist ein Funktionoid und warum sollte ich eines verwenden? (C ++ FAQ)