🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### Watchers WARNING: 下面这个章节要做一些更新,因为在Clojure1.1里面 `add-watcher` 和 `remove-watcher` 这两个函数被去掉了。 两个不大一样的函数 `add-watch` 和 `remove-watch` 被添加进来了。 Agents 可以用作其它几种引用类型的监视器。当一个被监视的引用的值发生了改变之后,Clojure会通过给Agent发送一个action的形式通知它。通知的类型可以是 `send` 或者 `send-off` , 这个是在你把Agent注册为引用类型的监视器的时候指定的。那个action的参数是那个监视器 Agent 以及发生改变的引用对象。这个action的返回值则是Agent的新值。 就像我们前面已经说过的那样,函数式编程强调那种“纯函数” -- 不会改变什么全局变量的函数。但是Clojure也不绝对静止这样做, 但是Clojure使得我们要找出对全局状态进行了改变的函数非常的简单。一个方法就是寻找那些能对状态进行改变的宏和方法,比如 `alter` 。 这到了调用这些宏/函数的地方就找到了所有修改全局状态的地方了。另外一个方法就是用Agent来监视对于全局状态的更改。一个监视者可以通过dump出来stack trace来确定到底是谁对全局状态做了修改。 下面的例子给一个Var,一个Ref, 一个Atom注册了一个Agent监视者。Agent里面维护了它所监视的每个引用被修改的次数(一个map)。这个map的key就是引用对象,而值则是被修改的次数。 ``` (def my-watcher (agent {})) (defn my-watcher-action [current-value reference] (let [change-count-map current-value old-count (change-count-map reference) new-count (if old-count (inc old-count) 1)] ; Return an updated map of change counts ; that will become the new value of the Agent. (assoc change-count-map reference new-count))) (def my-var "v1") (def my-ref (ref "r1")) (def my-atom (atom "a1")) (add-watcher (var my-var) :send-off my-watcher my-watcher-action) (add-watcher my-ref :send-off my-watcher my-watcher-action) (add-watcher my-atom :send-off my-watcher my-watcher-action) ; Change the root binding of the Var in two ways. (def my-var "v2") (alter-var-root (var my-var) (fn [curr-val] "v3")) ; Change the Ref in two ways. (dosync ; The next line only changes the in-transaction value ; so the watcher isn't notified. (ref-set my-ref "r2") ; When the transaction commits, the watcher is ; notified of one change this Ref ... the last one. (ref-set my-ref "r3")) (dosync (alter my-ref (fn [_] "r4"))) ; And now one more. ; Change the Atom in two ways. (reset! my-atom "a2") (compare-and-set! my-atom @my-atom "a3") ; Wait for all the actions sent to the watcher Agent to complete. (await my-watcher) ; Output the number of changes to ; each reference object that was watched. (let [change-count-map @my-watcher] (println "my-var changes =" (change-count-map (var my-var))) ; -> 2 (println "my-ref changes =" (change-count-map my-ref)) ; -> 2 (println "my-atom changes =" (change-count-map my-atom))) ; -> 2 (shutdown-agents) ```