在Clojure中,有更好的方法将事物构建为原子吗

  • 本文关键字:构建 方法 Clojure 更好 clojure
  • 更新时间 :
  • 英文 :


为了构建数据结构,我发现自己做了很多事情,比如:

(let [foo (atom [])]
(do
(swap! foo conj {:foo "bar"})
(swap! foo conj {:foo "baz"}))
@foo)
=> [{:foo "bar"} {:foo "baz"}]

这是反模式吗?我用了很多原子。

此处不需要atom。您可以使用不可变的数据结构:

(-> []
(conj {:foo "bar"})
(conj {:foo "baz"}))
;;=> [{:foo "bar"} {:foo "baz"}]

对于来自OOP或命令式语言的人来说,这可能是最难的转变:避免可变性。

首先,您不需要do,因为它隐含在let中。然后,对于这个例子,普通的旧->工作得很好(使用我最喜欢的模板项目(:

(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn stuff
[]
(-> []
(conj {:foo "bar"})
(conj {:foo "baz"})))

(dotest
(is= (stuff)
[{:foo "bar"}
{:foo "baz"}])

另一个选项是用户reduce:

(defn save-odds
[accum arg]
(if (odd? arg)
(conj accum arg)
accum))
<snip>
(is= (reduce save-odds
[]
(range 6))
[1 3 5]))

话虽如此,IMHO使用原子作为累加器并没有错。它很简单&直截了当的并且,如果";讨厌的";原子的突变永远不会泄漏到您的函数之外,它不会在程序的其余部分造成任何复杂性。

"如果发生突变并且没有外部功能受到影响真的很重要吗">

毕竟reduce和朋友们内部也使用突变,他们是"功能性";编程。也就是说,它们是纯函数(具有引用透明度(,不会产生副作用。

最新更新