2017-02-04 1 views
2

In Clojure werden die Variablen durch with-local-vars zugänglich durch Schließung definiert?Clojure mit-local-Vars in Schließung

Betrachten Sie das folgende Beispiel:

(defn foo [] 
     (with-local-vars [bar 10] 
      (fn [] @bar))) 

((foo)) 

Ergebnis ist die folgende: (. Stattdessen ich erwartete 10 zu bekommen)

#object[clojure.lang.Var$Unbound 0x131f68d8 "Unbound: #<Var: --unnamed-->"] 

C. F. mit folgendem:

(defn foo [] 
    (with-local-vars [bar 10] @bar)) 
(foo) 

Ergebnis: 10.

Basierend auf der documentation, ist es mir nicht klar, ob es gültig ist, lokale Vars in Clojure wie oben zu verwenden, aber ich würde vermuten, dass die Antwort nein ist. Kannst du das bitte bestätigen (oder widerlegen und erklären, was ich im ersten Beispiel falsch mache)? Und wenn meine Annahme klar ist (d. H., Dass lokale Variablen nicht in der Schließung verwendet werden können), dann erkläre, was der Grund dafür ist?

EDIT: für die Datensätze, this is the problem I was trying to solve.

Antwort

6

Die Dokumentation für with-local-vars scheint nicht besonders hier klar. Es sagt nur, dass es Thread-lokale Bindungen für die Variablen erstellt, aber nichts darüber sagt, was mit ihnen geschieht, wenn Sie den Bereich with-local-vars verlassen.

Im Gegensatz dazu gibt die with-bindings documentation explizit an, dass die thread-local-Bindungen beim Verlassen dieses Bereichs freigegeben werden.

Wenn Sie sich den Quellcode schauen, können Sie sehen, dass beide with-local-vars und with-bindings implementiert die gleichen grundlegenden Mechanismen (pushThreadBindings und popThreadBindings), die sie andeuten, dass fast identisches Verhalten haben.

Also ja, Sie haben Recht, Sie können nicht erwarten, dass die with-local-vars Werte in einem Verschluss außerhalb des with-local-vars Geltungsbereich erfasst werden. Allerdings sieht Clojure den bound-fn Mechanismus speziell für diese Art des Verschlusses, die alle mit den aktuellen lokalen Thread-Bindungen erfassen:

(def foo (with-local-vars [bar 10] (fn [] @bar))) 
(foo) 
; => #object[clojure.lang.Var$Unbound 0x60063e12 "Unbound: #<Var: --unnamed-->"] 

(def baz (with-local-vars [bar 10] (bound-fn [] @bar))) 
(baz) 
; => 10 
+0

Danke für die schnelle Antwort, scheint dies in der Tat der richtige Weg zu sein, der Verwendung von lokalen Variablen in die Schließung. Es ist schön, etwas Neues zu lernen :) Unglücklicherweise löst es mein ursprüngliches Problem nicht, da es so aussieht, als ob der Wert der lokalen Variablen bei jedem Aufruf der zurückgegebenen Funktion "zurückgesetzt" wird (siehe auch die verknüpfte CodeReview - Frage in die EDIT für Details). – Attilio

+1

@Attilio - Es ist mir nicht klar, was Ihr erwartetes Verhalten ist (in Ihrer anderen Frage). Was, wenn Sie nur die 'mit-lokalen-vars' in Ihrer' logfun' Definition mit '(lassen Sie [depth (atom 0)] ...) ersetzen? Liefert das das Verhalten, nach dem Sie suchen? Wenn nicht, können Sie versuchen, das 'let' * außerhalb * des' defn logfun' zu verschieben (wodurch 'logfun' über' Tiefe' schließen kann, ohne es zu einer globalen Definition zu machen). – DaoWen