所以,我刚刚开始学习 Clojure,现在面临着一个无法通过 google 解决的问题。
这是我的 atm 代码:
=> (def a "asd")
=> a
"asd"
=> (defn bla [entry_value] (def entry_value "qwe"))
=> (bla a)
#'exercise.core/entry_value
=> a
"asd"
=> entry_value
"qwe"
我真正想要的是a具有“qwe”作为价值。 可以吗?
感谢您的帮助!
是的,从技术上讲,可以借助像这样的alter-var-root函数
=> (defn bla [entry-value] (alter-var-root entry-value (fn [_] "qwe")))
=> #'user/bla
=> (def a "asd")
=> #'user/a
=> (bla #'a)
=> "qwe"
=> a
=> "qwe"
但这不是 Vars(用
def
定义的东西)在 Clojure 中的工作方式。 def
用于在 Clojure 中声明绑定,而不是变量。 Binding 意味着您将某个值绑定到某个名称,并且它将来不会改变,例如该绑定是不可变的。程序中的其他函数可能依赖于这种不变性,因此请不要使用 alter-var-root
或其他更改代码中绑定的方法。
如果您确实需要某种具有可变状态的变量 - 请使用
atoms
。
我鼓励您阅读“Clojure 勇敢而真实”,其中包含有关该主题的非常好的和简洁的解释。
关于“使用 Def 命名值”部分下的
def
此处。
this online repl
之前已经是 def
(已声明)
dynamic
,你可以让它得到,让我们说 [暂时 | ]保持不变性]用新值呈现,如下所示:
编辑:参考文献例如here
(def ^:dynamic x 5) ;; =>#'user/x
(def ^:dynamic y 3) ;; =>#'user/y
x ;=> 5
y ;=> 3
(binding [x 2 y 7] (+ x y)) ;=> 9
(+ x y) ;=> 8
(defn add-val [] (+ x y)) ;=>#'user/add-val
(binding [x 3 y 7] (add-val)) ;=> 10
(+ x y) ;=> 8 x y still immutable values
(bla a)
,首先发生的事情是字符串“a”被
a
的内容替换。您的电话实际上是(bla "asd")
。变量的名称消失了。所以函数对你没有帮助。如果您通过了其他未评估的内容,则可以解决此问题。这可以是字符串,也可以是 Anton Chikin 提出的东西。但这样的解决方案始终是句法妥协。
您可能想要的是一个宏。在宏中,参数不被求值。这就是宏的用途。
您有两种选择来实现这一目标。
(defmacro bla [entry_value] `(def ~entry_value "qwe"))
或
(defmacro bla [entry_value] (list 'def entry_value "qwe"))
您可以看到它的作用
(macroexpand-1 '(bla a))
然而,好处是有限的。这不是动态行为。宏只是一个语法快捷方式。你可能想做类似的事情
(let [var a] (bla var))
或
(let [var 'a] (bla var))
。但这不适用于宏。您可能已经看到了问题。当输入此内容时,事情已经被评估并且宏也被立即评估。同样不起作用的是从命名空间外部更改a
。
但这仍然是编写宏的一个很好的练习。