使用“def”之间的差异以更新var和“alter-var-root” [英] Difference between using "def" to update a var and "alter-var-root"

查看:180
本文介绍了使用“def”之间的差异以更新var和“alter-var-root”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用def更新var和使用alter-var-root有什么区别?
eg

 (def x 3)
(def x(inc x))



vs

  (def x 3)
(alter-var-root#'x inc)


解决方案

我发现alter-var-root很少出现在惯用的Clojure代码中;不是有任何错误,它只是为角落情况。如果你发现自己使用它来构建循环,这是一个标志,需要一个不同的方法。我主要看到它在初始化例程中设置访问凭据或记录器等。



alter-var-root 使用函数机械地更改var的值,而 def 只是将它设置为一个新值。在您的示例中,它们是等价的。

  hello.exp& (def foo 4)
#'hello.exp / foo
hello.exp> (alter-var-root#'foo inc)
5
hello.exp> foo
5

alter-var-root 也不愿意创建一个新的var:

  hello.exp> (alter-var-root#'foo1 inc)
CompilerException java.lang.RuntimeException:无法解析var:foo1在此上下文中,编译:(NO_SOURCE_PATH:1)

alter-var-root 也可以用于其他命名空间:

  hello.exp> (in-ns'user)
#< Namespace user>
user> (alter-var-root#'hello.exp / foo inc)
6
user> (def hello.exp / foo 4)
CompilerException java.lang.RuntimeException:无法在当前ns之外创建def,编译:(NO_SOURCE_PATH:1)
user>

这最后一个用例是我在实践中唯一需要的。例如强制 clojure.logging 使用正确的slf4j记录器作为Pallet项目的示例:

 $ (defn force-slf4j 
repl任务带来commons-logging,这会使我们的日志记录
配置混乱,这是一个尝试恢复理性
[]
(binding [* ns *(the-ns'clojure.tools.logging.slf4j)]
(alter-var-root
#'clojure.tools.logging / * logger -factory *
(不断(clojure.tools.logging.slf4j / load-factory)))))

这是使用 alter-var-root 来重置另一个命名空间中的var,而不管它在初始化时的内容。我想这是一个黑客...


What's the difference between using "def" to update a var and using "alter-var-root"? e.g.

(def x 3)
(def x (inc x))

vs

(def x 3)
(alter-var-root #'x inc)

解决方案

I find alter-var-root very rarely comes up in idiomatic Clojure code; not that there is anything wrong with it, it's just intended for corner cases. If you find yourself using it to build loops and such it's a sign something needs a different approach. I mostly see it in initialization routines for setting access credentials or loggers and such.

alter-var-root uses a function to mechanically change the value of a var while def just sets it to a new value. In your example they are equivalent.

hello.exp> (def foo 4)
#'hello.exp/foo
hello.exp> (alter-var-root #'foo inc)
5
hello.exp> foo
5

alter-var-root is also unwilling to create a new var:

hello.exp> (alter-var-root #'foo1 inc) 
CompilerException java.lang.RuntimeException: Unable to resolve var: foo1 in this context, compiling:(NO_SOURCE_PATH:1) 

alter-var-root can work on other namespaces as well:

hello.exp> (in-ns 'user)
#<Namespace user> 
user> (alter-var-root #'hello.exp/foo inc) 
 6
user> (def hello.exp/foo 4)
CompilerException java.lang.RuntimeException: Can't create defs outside of current ns, compiling:(NO_SOURCE_PATH:1)
user>

This last use case is the only one I have ever needed in practice. For instance forcing clojure.logging to use the correct slf4j logger as an example from the Pallet project:

(defn force-slf4j
  "The repl task brings in commons-logging, which messes up our logging
   configuration. This is an attempt to restore sanity."
   []
  (binding [*ns* (the-ns 'clojure.tools.logging.slf4j)]
    (alter-var-root
     #'clojure.tools.logging/*logger-factory*
     (constantly (clojure.tools.logging.slf4j/load-factory)))))

Which is just using alter-var-root to reset a var in another namespace regardless of its content on initialization. I suppose it's a bit of a hack ...

这篇关于使用“def”之间的差异以更新var和“alter-var-root”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆