【问题标题】:Clojure: Update map inside a methodClojure:在方法内更新地图
【发布时间】:2020-06-29 04:58:56
【问题描述】:

我有一个用例,我想在方法调用中更新我的map 类型变量之一。这里要演示的是一段代码sn -p,

(defn func [mymap]
    (conj mymap [1 2])) ;update mymap variable here such that changes are persistent after the method returns

(let [mymap {}
    _ (func mymap)] (println mymap))

它输出{},因为我认为使用conj 函数创建了一个新地图。如何更新func 中的mymap 变量,使上述程序的输出为{1 2}

如果在 Clojure 中不可能,一般如何处理此类用例?

【问题讨论】:

    标签: dictionary clojure


    【解决方案1】:

    很多选择。最简单的是重新绑定mymap 变量。考虑:

    (ns tst.demo.core
      (:use tupelo.core tupelo.test))
    
    (defn doit [mymap]
          (into mymap {:b 42}))
    
    (dotest
      (let [m {:a 1}
            m2 (doit m)]
        (spyx m2)))
    
    m2 => {:a 1, :b 42}
    

    我们得到了我们期望的结果。 更新代码以重用名称m

    (dotest
      (let [m {:a 1}
            m (doit m)]
        (spyx m)))
    
    m => {:a 1, :b 42}
    

    这里m 的第二次使用创建一个单独的变量,它遮蔽第一个m。这很有效,而且人们总是不经意间就这样做了,甚至没有意识到。

    如果你想复制 Java 的行为,你需要一个 Clojure atom 来创建一个可变的存储位置。

    (dotest
      (let [m-atom (atom {:a 1})]
        (swap! m-atom doit)
        (spyx @m-atom)))
    
    (deref m-atom) => {:a 1, :b 42}
    

    在这里交换!将函数 doit 应用于 contentsm-atom,将结果作为新内容

    我们需要@m-atom(deref m-atom) 来提取要打印的原子内容。

    以上便捷功能可以是found here。我在this template project 中也有一些很棒的文档参考。尤其要确保每天学习 Clojure 备忘单。

    【讨论】:

      【解决方案2】:

      Clojure 默认使用不可变数据类型。这意味着,您不能 像你习惯的那样从其他许多地方改变数据 编程语言。

      这里的函数式方法是使用来自conj 的结果( defn 中的最后一条语句是它的返回值)。

      (let [mymap {} 
            result (func mymap)]
        (println result))
      

      你可以在不可变数据上跟上纯函数的时间越长 你的生活会更轻松;推理你的程序和测试 他们变得容易多了。

      当然可以选择使用 Java 中的可变数据类,但是 除非您真的必须这样做,否则不要使用它们。

      而且由于几乎所有程序都需要一些状态,所以还有atom:s

      • 这里只提这个,因为到处都缺少defatom 到处都是初学者遇到的下一个最佳“陷阱”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-12-18
        • 1970-01-01
        • 2021-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多