Đã cập nhật để nhận xét của Stuart Sierra (đề cập clojure.core/intern
) vào tài khoản.
Sử dụng eval
đây là điều tốt, nhưng có thể thú vị khi biết rằng nó không cần thiết, bất kể Vars có tồn tại hay không. Trong thực tế, nếu chúng được biết là tồn tại, thì tôi nghĩ giải pháp alter-var-root
dưới đây là sạch hơn; nếu chúng có thể không tồn tại, thì tôi sẽ khăng khăng yêu cầu thay thế của tôi là sạch hơn nhiều, nhưng nó dường như làm cho mã ngắn nhất (nếu chúng ta bỏ qua chi phí của ba dòng cho định nghĩa hàm), vì vậy tôi sẽ đăng nó để bạn xem xét.
Nếu Var được biết là tồn tại:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
Vì vậy, bạn có thể làm
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(Nếu giá trị tương tự đã được sử dụng cho tất cả Vars, bạn có thể sử dụng (repeat value)
cho đối số cuối cùng để ánh xạ hoặc chỉ đặt nó vào hàm ẩn danh.)
Nếu Vars có thể cần phải được tạo ra, sau đó bạn có thể thực sự viết một chức năng để làm điều này (một lần nữa, tôi sẽ không nhất thiết phải khẳng định điều này là sạch hơn eval
, nhưng dù sao - chỉ cho vì lợi ích của nó):
(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)))
Lưu ý rằng nếu một Var hóa ra đã được thực tập nội trú với tên được đặt trong không gian tên nào đó, thì đây có gì thay đổi trong trường hợp đối số duy nhất hoặc chỉ reset Var đến đưa ra giá trị mới trong hai trường hợp đối số. Với điều này, bạn có thể giải quyết vấn đề ban đầu như vậy:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Một số ví dụ bổ sung:
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
Câu trả lời ngắn gọn và đơn giản nhất (có thể?). Tôi đã đưa cho bạn dấu tick và hy vọng sepp2k không phải là điên về mất nó. Cảm ơn! –