Wann sollte ein Var anstelle einer Funktion verwendet werden?

7

Ich gehe durch das Clojure-Webentwicklungsbuch und es sagt mir, dass ich das Handler-var-Objekt (definiert unten) anstelle der Funktion selbst übergeben soll, da sich die Funktion dynamisch ändern wird (das ist was Wrap-Reload tut).

Das Buch sagt:

"Beachten Sie, dass wir für diese Middleware eine Variable aus dem Handler erstellen müssen arbeiten. Dies ist notwendig, um sicherzustellen, dass das Var-Objekt den aktuellen enthält Handler-Funktion wird zurückgegeben. Wenn wir stattdessen den Handler verwenden würden, würde die App dies tun sehe nur den ursprünglichen Wert der Funktion und Änderungen werden nicht berücksichtigt. " Ich verstehe nicht wirklich, was das bedeutet, sind vars ähnlich wie c-Zeiger?

%Vor%

Hier ist der Handler-Aufruf:

%Vor%     
Maurex 17.09.2016, 18:47
quelle

3 Antworten

11

Ja, die Variable ähnelt einem C-Zeiger. Dies ist schlecht dokumentiert.

Angenommen, Sie definieren fred wie folgt:

%Vor%

Es gibt tatsächlich 3 Dinge hier. Erstens ist fred ein Symbol. Es gibt einen Unterschied zwischen einem Symbol% ​​co_de% (keine Anführungszeichen) und dem Schlüsselwort fred (markiert durch das führende :fred char) und der Zeichenkette : (an beiden Enden durch ein Anführungszeichen gekennzeichnet). Zu Clojure besteht jeder von ihnen aus 4 Zeichen; d.h. weder der Doppelpunkt des Schlüsselworts noch die doppelten Anführungszeichen der Zeichenfolge sind in ihrer Länge oder Zusammensetzung enthalten:

%Vor%

Der einzige Unterschied besteht darin, wie sie interpretiert werden. Eine Zeichenfolge soll Benutzerdaten beliebiger Art darstellen. Ein Schlüsselwort soll Steuerinformationen für das Programm in einer lesbaren Form darstellen (im Gegensatz zu "magischen Zahlen" wie 1 = links, 2 = rechts, verwenden wir nur die Schlüsselwörter "fred" und :left .

Ein Symbol soll auf Dinge verweisen, genau wie in Java oder C. Wenn wir sagen

%Vor%

then :right zeigt auf den Wert 1, x zeigt auf den Wert 2, und wir sehen das Ergebnis gedruckt.

Das Formular y führt ein unsichtbares drittes Element ein, das (def ...) . Also wenn wir

sagen %Vor%

Wir haben jetzt 3 Objekte zu beachten. var ist ein Symbol, das auf ein wilma zeigt, das wiederum auf den Wert var zeigt. Wenn unser Programm auf das Symbol% ​​co_de% trifft, wird ausgewertet , um 3 zu finden. Entsprechend wird die Variable ausgewertet , um den Wert 3 zu erhalten. Es ist also wie eine 2-Level-Indirektion von Zeigern in C. Da sowohl das Symbol als auch stark> die Var sind "automatisch ausgewertet", dies geschieht automatisch und unsichtbar und Sie müssen nicht über die Var nachdenken (in der Tat, die meisten Menschen sind sich nicht wirklich bewusst, dass der unsichtbare mittlere Schritt überhaupt existiert).

Für unsere obige Funktion wilma existiert eine ähnliche Situation, außer dass die var-Punkte auf die anonyme Funktion var anstatt auf den Wert fred wie auf (fn [x] (+ x 1)) verweisen.

Wir können die automatische Auswertung der Variablen wie folgt "kurzschließen":

%Vor%

oder

%Vor%

wo das Leser-Makro 3 (Pfund-Quote) eine Abkürzung ist, um die spezielle Form wilma aufzurufen. Beachten Sie, dass eine spezielle Form wie #' ein eingebauter Compiler wie 'if' oder 'def' ist und nicht mit einer regulären Funktion übereinstimmt. Das spezielle Formular (var ...) gibt das Objekt var zurück, das an das Symbol% ​​co_de% angehängt ist. Die Clojure-REPL druckt das Objekt var mit der gleichen Kurzschrift, so dass beide Ergebnisse gleich aussehen.

Sobald wir das var-Objekt haben, ist die automatische Auswertung deaktiviert:

%Vor%

Wenn wir zu dem Wert gelangen wollen, auf den var zeigt, müssen wir wilma :

verwenden %Vor%

Das Gleiche funktioniert für Fred:

%Vor%

wo der var stuff Clojures Methode ist, ein Funktionsobjekt als String darzustellen.

Was den Webserver betrifft, kann er über die wilma -Funktion oder anderweitig erkennen, ob der übergebene Wert die Handler-Funktion oder die Variable ist, die auf die Handler-Funktion zeigt.

Wenn Sie etwas wie folgt eingeben:

%Vor%

Die doppelte automatische Auswertung liefert das Handler-Funktionsobjekt, das an var-get übergeben wird. Wenn Sie stattdessen Folgendes eingeben:

%Vor%

dann wird das #object[clj.core$fred ...] , das auf das Handler-Funktionsobjekt verweist, an var? übergeben. Dann muss run-jetty eine var -Anweisung oder eine Äquivalenz verwenden, um zu bestimmen, was es erhalten hat, und run-jetty aufrufen, wenn es eine run-jetty anstelle einer Funktion erhalten hat. Somit gibt jedes Mal durch if das Objekt zurück, auf das der (var-get ...) aktuell zeigt. So verhält sich var wie ein globaler Zeiger in C oder eine globale "Referenz" -Variable in Java.

Wenn Sie ein Funktionsobjekt an (var-get ...) übergeben, speichert es einen "lokalen Zeiger" auf das Funktionsobjekt und es gibt keine Möglichkeit für die Außenwelt zu ändern, worauf der lokale Zeiger verweist.

Hier finden Sie weitere Details:

Alan Thompson 17.09.2016, 19:18
quelle
7

Hoffentlich bringt dich dieses kleine Beispiel auf den richtigen Weg:

%Vor%

Die Intuition dafür besteht darin, dass Sie bei der Erstellung eines Handlers einen "Container" mit einem gewissen Wert übergeben, dessen Inhalt in Zukunft geändert werden kann, indem Sie var mit demselben Namen definieren. Wenn Sie nicht var (wie in your-app-without-var ) verwenden, übergeben Sie einen aktuellen Wert dieses "Containers", der in keiner Weise neu definiert werden kann.

    
OlegTheCat 17.09.2016 19:30
quelle
7

Es gibt schon einige gute Antworten. Ich wollte nur diesen Vorbehalt hinzufügen:

%Vor%

Wenn also direkte Verknüpfung aktiviert ist, wird die Indirektion über ein var durch einen direkten statischen Aufruf ersetzt. Ähnlich der Situation mit dem Handler, aber dann mit jedem var-Aufruf, es sei denn, Sie verweisen explizit auf eine Variable wie:

%Vor%     
Michiel Borkent 17.09.2016 20:48
quelle

Tags und Links