简体   繁体   English

Clojure:在方法内更新 map

[英]Clojure: Update map inside a method

I have a use case where I want to update one of my map type variables inside a method call.我有一个用例,我想在方法调用中更新我的map类型变量之一。 To demonstrate here is a code snippet,为了演示这里是一个代码片段,

(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))

which outputs {} because I think a new map is created with the conj function.输出{}因为我认为使用conj function 创建了一个新的 map。 How do I update the mymap variable in func such that the output of the above program will be {1 2} ?如何更新func中的mymap变量,使上述程序的 output 为{1 2}

If it is not possible in Clojure, how are such use cases handled in general?如果在 Clojure 中不可能,一般如何处理此类用例?

Many choices.很多选择。 Simplest is to rebind the mymap variable.最简单的是重新绑定mymap变量。 Consider:考虑:

(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}

and we get what we expect.我们得到了我们所期望的。 Update the code to reuse the name m :更新代码以重用名称m

(dotest
  (let [m {:a 1}
        m (doit m)]
    (spyx m)))

m => {:a 1, :b 42}

Here the 2nd usage of m creates a separate variable that shadows the first m .这里m的第二次使用创建了一个单独的变量隐藏第一个m This works great and people do it accidentally all the time without even realizing it.这很好用,人们总是在不经意间做这件事,甚至没有意识到。

If you want to copy the behavior of Java, you need a Clojure atom to create a mutable storage location.如果要复制 Java 的行为,则需要一个 Clojure atom来创建可变存储位置。

(dotest
  (let [m-atom (atom {:a 1})]
    (swap! m-atom doit)
    (spyx @m-atom)))

(deref m-atom) => {:a 1, :b 42}

Here swap!这里换! applies the function doit to the contents of m-atom , the puts the results as the new contents .将 function doit应用于m-atom内容,将结果作为新内容

We need the @m-atom or (deref m-atom) to pull out the contents of the atom for printing.我们需要@m-atom(deref m-atom)来提取原子的内容以进行打印。

The above convenience functions can be found here .上述便利功能可在此处找到 I also have some great documentation references in this template project .我在这个模板项目中也有一些很棒的文档参考。 Be especially sure to study the Clojure Cheatsheet daily.特别要确保每天学习 Clojure 备忘单。

Clojure uses immutable data types by default. Clojure 默认使用不可变数据类型。 This means, you cannot mutate the data in place like you are used to from many other programming languages.这意味着,您不能像从许多其他编程语言中习惯的那样对数据进行原地变异。

The functional approach here is to use the result from the conj (the last statement inside a defn is it's return value).这里的函数式方法是使用conj的结果( defn中的最后一条语句是它的返回值)。

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

The longer you can keep up with pure functions on immutable data the easier your life will be;您可以在不可变数据上跟上纯函数的时间越长,您的生活就会越轻松; reasoning about your programs and testing them becomes a lot easier.推理您的程序并对其进行测试变得容易得多。

There is of course the option to use mutable data classes from Java, but don't use them unless you really have to.当然可以选择使用 Java 中的可变数据类,但除非你真的必须,否则不要使用它们。

And since nearly all programs need some state, there are also atom :s而且由于几乎所有程序都需要一些 state,因此还有atom :s

  • I only mention this here, because short of def everywhere, atom everywhere are the next best "trap" beginners run into.我在这里只提到这一点,因为缺少def ,到处都是atom是初学者遇到的下一个最佳“陷阱”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM