Clojure - 如何自动初始化一次

时间:2014-05-15 19:33:54

标签: clojure

我使用的代理引用了一个集合来跟踪我需要通知事件的用户。我希望它在第一次调用时自动初始化,所以这就是我到目前为止所做的:

(declare notify-users!)

(def users-to-notify
  (future
    (def _utn (agent #{}))
    (add-watch _utn :utn notify-users!)
    _utn))

(defn update-user [user-id]
  (send-off @users-to-notify conj user-id))

(defn notify-users! [key reference old-state new-state]
  (println old-state " -> " new-state))

这似乎有效,但我想知道这种方法有任何问题我都不知道。

1 个答案:

答案 0 :(得分:1)

我自己仍然是学习者,但我想我可以帮助你以更惯用的方式表达你所写的内容。

首先,在开始使用之前定义辅助函数,除非有特定原因要首先声明它们。我用这种方式测试了代码,多次,它工作正常。

(defn notify-users [key reference old-state new-state]
  (println old-state " -> " new-state))

(defonce users-to-notify
  (future
    (let [utn (agent #{})]
    (add-watch utn :utn notify-users)
    utn)))

(defn update-user! [user-id]
  (send-off @users-to-notify conj user-id))

另外,也许这是一个风格问题,但我通常只在顶级使用def,以避免混淆下一个程序员通过我的代码阅读的范围。在这种情况下,let更好,如果您测试它,您将看到代理在用户通知var中持续存在。感叹号用于表示变异函数,而不是副作用函数,通常下划线用于指示作为参数传递给函数的值,该值不会在结果代码中使用。在使用需要绑定的dotimes函数时可以找到一个常见示例:

(dotimes [_ 10] (println "I'm a cheeky monkey!"))

我也将def更改为defonce,但是你应该注意defonce不是线程安全的,这意味着expr可以被多次评估。