Clojure 中的 def 和 defonce 有什么区别?

What is the difference between def and defonce in Clojure?

Clojure 中的 defdefonce 有什么区别?

何时使用 def 而不是 defonce 或相反?

defonce 当变量已经定义时被跳过。

user> (def a 1) ;;=> #'user/a
user> a ;;=> 1
user> (def a 2) ;;=> #'user/a
user> a ;;=> 2
user> (defonce b 1) ;;=> #'user/b
user> b ;;=> 1
user> (defonce b 2) ;;=> nil
user> b ;;=> 1

如果名称没有根值,Defonce 只会将名称绑定到根值。

比如像Jay Fields blogsabout,当你想重新加载命名空间但可能不需要全部重新加载时,它可以结合使用。

(defonce ignored-namespaces (atom #{}))

(defn reload-all []   
  (doseq [n (remove (comp @ignored-namespaces ns-name) (all-ns))]
    (require (ns-name n) :reload )))

至于什么时候使用defonce,如果你正在使用带热重载的系统(例如带挂载的 CLJS 和 re-frame),defonce 有助于保持状态在重新加载之间。

当您自己 re-evaluate 源文件(例如在 REPL 中)但希望将 var 的值保持绑定到符号时的类似情况。