给定变量的名称列表,我想将这些变量设置为一个表达式。
我试过这个:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but这会产生错误
java.lang.Exception:定义的第一个参数必须是符号
有人能告诉我完成这件事的正确方法吗?
发布于 2010-03-28 03:42:35
Clojure的"intern“函数就是为了这个目的:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
发布于 2010-03-21 20:04:30
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
对您的评论的回应:
这里没有涉及宏。eval
是一个函数,它接受一个列表,并以代码的形式返回执行该列表的结果。`和~是创建部分引用列表的快捷方式。
`表示以下列表的内容应加引号,除非前面有~
~下面的列表是应该执行的函数调用,而不是引号。
所以(def ~(symbol x) 666)is the list containing the symbol
def, followed by the result of executing
symbol xfollowed by the number of the beast. I could as well have written
(is the list containing the symbol
(list 'def (symbol x) 666))`也可以达到同样的效果。
发布于 2010-03-22 01:12:43
更新以考虑斯图亚特·塞拉的评论(提到clojure.core/intern
__)。
在这里使用eval
是很好的,但是知道它不是必需的可能很有趣,不管Vars是否已知已经存在。事实上,如果已知它们存在,那么我认为下面的alter-var-root
解决方案更简洁;如果它们可能不存在,那么我不会坚持我的替代方案更简洁,但它似乎有利于最短的代码(如果我们忽略了函数定义的三行开销),所以我将其张贴出来供您考虑。
如果已知Var存在:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
所以你可以这样做
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(如果要对所有Var使用相同的值,则可以使用(repeat value)
作为最后一个参数进行映射,或者直接将其放入匿名函数中。)
如果可能需要创建Vars,那么您实际上可以编写一个函数来完成这项工作(再次声明,我不一定声称它比eval
更干净,但不管怎样--只是出于兴趣):
(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)))
请注意,如果一个Var已经在给定的名称空间中使用了给定的名称,那么在单参数的情况下不会改变任何东西,或者在两个参数的情况下只是将Var重置为给定的新值。这样,您就可以像这样解决原始问题:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
一些额外的例子:
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
https://stackoverflow.com/questions/2486752
复制相似问题