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%Ja, die Variable ähnelt einem C-Zeiger. Dies ist schlecht dokumentiert.
Angenommen, Sie definieren fred
wie folgt:
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:
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
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
:
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:
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:
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.
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%