【问题标题】:Save state on clojure在 clojure 上保存状态
【发布时间】:2018-09-03 23:53:54
【问题描述】:

我现在开始使用函数式编程,并且对没有变量的工作感到非常疯狂。

我阅读的每个教程都说重新定义变量并不酷,但我不知道如何在不将状态保存在变量上的情况下解决我的实际问题。

例如:我正在开发一个 API,我想通过请求保留这些值。假设我有一个添加person 的端点,并且我有一个persons 的列表,我想redefine 或更改我的persons 列表的值添加新的person。我该怎么做?

是否可以使用var-setalter-var-rootconj!

(对于我正在使用的 api compojure-api 并且每个 person 将是一个 Hash

【问题讨论】:

    标签: clojure compojure ring compojure-api


    【解决方案1】:

    您可能在大型应用程序的某个地方需要一个可变状态,但并非在所有情况下都需要。

    我不熟悉 compojure,但这里有一个使用不变性的小例子,它可能会给你一个更好的主意:

    (loop [requests []
           people []
    
       (let [request (receive-request)]
         ; Use requests/people
    
         ; Then loop again with updated lists
         (recur (conj requests request)
                (conj people (make-person request))))])
    

    我在这里使用假设的 receive-requestmake-person 函数。

    loop 创建一对绑定,并在每个 recur 更新它们。这是“重新定义变量”的简单方法。这类似于纯递归,您不会在任何时候改变最终结果,您只需更改传递给下一次迭代的值。

    当然,这非常简单,而且不切实际,因为您一次只收到一个请求。如果您同时接收来自多个线程的请求,这对于原子来说是合理的:

    (defn listen [result-atom]
      (Thread.
        (fn []
          (while true ; Infinite listener for simplicity
            (let [request (receive-request)]
              (swap! result-atom #(conj % (make-person request))))))))
    
    (defn listen-all []
      (let [result-atom (atom [])]
        (listen result-atom)
        (listen result-atom)))
        ; result-atom now holds an updating list of people that you can do stuff with
    

    swap! 通过conjoining 将原子变异到它持有的列表中。原子内部的列表没有发生突变,它只是被自身的修改版本替换。 任何持有对旧人员名单的引用的人都不会受到对swap!的调用的影响

    更好的方法是使用 core/async 之类的库,但这已经脱离了问题。

    关键是,您可能需要在某处使用可变变量,但对它们的需求比您习惯的要少得多。在大多数情况下,几乎所有事情都可以使用第一个示例中的不变性来完成。

    【讨论】:

      【解决方案2】:

      Clojure 将值与身份区分开来。您可以使用原子来管理您的 compojure 应用程序中的状态。

      (def persons (atom [])) ;; init persons as empty vector
      (swap! persons #(conj % {:name "John Doe"})) ;; append new value
      

      您可以在文档中找到更多信息:

      https://clojure.org/reference/atoms

      https://clojure.org/reference/data_structures

      https://clojuredocs.org/clojure.core/atom

      【讨论】:

      • 注意原子交换值(因此是“交换!”),这个操作与设置变量不太一样。您可以使用 reset! 来“设置”该值,但更好的用途是通过对其应用函数来更改该值,如上例所示。原子没有竞争条件,因此它们可以安全地同时使用。最初,在您的代码中存在大量原子是正常的,但最终您会非常稀疏地使用它们,并且大部分代码只是通过函数传递值。
      猜你喜欢
      • 1970-01-01
      • 2014-07-22
      • 1970-01-01
      • 2023-03-27
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多