Zaktualizowano komentarz Stuarta Sierra (z podaniem clojure.core/intern
).
Stosowanie tutaj jest w porządku, ale może być interesujące wiedzieć, że nie jest to konieczne, niezależnie od tego, czy Vars są już znane. W rzeczywistości, jeśli są znane, to myślę, że poniższe rozwiązanie jest czystsze; gdyby nie istniały, to nie nalegałbym, by moja alternatywna propozycja była znacznie czystsza, ale wydaje się, że jest to najkrótszy kod (jeśli pominiemy narzut z trzech linii dla definicji funkcji), więc po prostu opublikuję to dla twojego rozważenia.
Jeśli Var jest znany istnieją:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
Więc można zrobić
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(Jeśli ta sama wartość miał być stosowany dla wszystkich Vars, można użyć (repeat value)
dla końcowego argumentu do mapowania lub po prostu umieść go w anonimowej funkcji.)
Jeśli Vars może muszą być tworzone, a następnie rzeczywiście można napisać funkcję, aby to zrobić (po raz kolejny, nie koniecznie twierdzą, że jest to czystsze niż eval
, ale w każdym razie - tylko dla odsetki od niego):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Zauważ, że jeśli Var okazuje się już internowany o podanej nazwie w danej przestrzeni nazw, to nic nie zmienia w przypadku jeden argument lub po prostu resetuje Var do podana nowa wartość w przypadku dwóch argumentów. Dzięki temu można rozwiązać pierwotnego problemu tak:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
kilka dodatkowych przykładów:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Najbardziej zwięzła i bezpośrednia (możliwa?) Odpowiedź. Dałem ci znak i nadzieję, że sepp2k nie jest szalony, że go stracił. Dzięki! –