已根据Stuart Sierra的评论(提到clojure.core/intern
)进行更新。
在这里使用eval
是没有问题的,但值得注意的是,无论变量是否已知存在,都不需要使用它。实际上,如果它们已知存在,那么我认为下面的alter-var-root
解决方案更加简洁;如果可能不存在,则我不会坚持我的替代命题要更加简洁,但是它似乎可以生成最短的代码(如果我们忽略三行函数定义的开销),所以我将其发布供您考虑。
如果变量已知存在:
(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]))
如果所有的变量都需要使用相同的值,你可以在map的最后一个参数中使用(repeat value)
或者将其放入匿名函数中。
如果需要创建Vars,那么你可以编写一个函数来完成这个任务(再次强调,我并不一定认为这比eval
更干净,但是出于兴趣,我们可以这样做):
(defn create-var
([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
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5