在 Clojure 中,如何更改(def)函数内的变量值

问题描述 投票:0回答:3

所以,我刚刚开始学习 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”作为价值。 可以吗?

感谢您的帮助!

clojure
3个回答
4
投票

是的,从技术上讲,可以借助像这样的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

测试上面的代码。


2
投票
var

之前已经是 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



0
投票
(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

但这仍然是编写宏的一个很好的练习。

© www.soinside.com 2019 - 2024. All rights reserved.