如果您正在与 Java 代码交互,您可能不得不硬着头皮以 Java 的方式进行,使用.put
. 这不一定是大罪;Clojure 为您提供了类似的东西do
,.
特别是让您可以轻松地使用 Java 代码。
assoc
仅适用于 Clojure 数据结构,因为已经进行了大量工作以非常便宜地创建它们的新(不可变)副本,只需稍作改动。Java HashMap 并非旨在以相同的方式工作。每次进行更改时,您都必须继续克隆它们,这可能会很昂贵。
如果您真的想摆脱 Java 变异领域(例如,也许您将这些 HashMaps 保留很长时间并且不希望 Java 调用到处都是,或者您需要通过print
and序列化它们read
,或者您想要使用 Clojure STM 以线程安全的方式使用它们)您可以轻松地在 Java HashMap 和 Clojure 哈希映射之间进行转换,因为 Clojure 数据结构实现了正确的 Java 接口,因此它们可以相互通信。
user> (java.util.HashMap. {:foo :bar})
#<HashMap {:foo=:bar}>
user> (into {} (java.util.HashMap. {:foo :bar}))
{:foo :bar}
如果你想要一个类似do
- 的东西,一旦你完成了它就会返回你正在处理的对象,你可以使用doto
. 事实上,Java HashMap 在官方文档中用作该函数的示例,这再次表明,如果您使用 Java 对象(明智地),这不是世界末日。
clojure.core/doto
([x & forms])
Macro
Evaluates x then calls all of the methods and functions with the
value of x supplied at the front of the given arguments. The forms
are evaluated in order. Returns x.
(doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
一些可能的策略:
如果可以的话,将你的突变和副作用限制在一个函数中。如果您的函数在给定相同输入的情况下始终返回相同的值,则它可以在内部做任何想做的事情。有时,改变数组或映射是实现算法的最有效或最简单的方法。只要您不向世界其他地方“泄漏”副作用,您仍然会享受函数式编程的好处。
如果您的对象将存在一段时间,或者它们需要与其他 Clojure 代码很好地配合,请尝试尽快将它们放入 Clojure 数据结构中,并在最后一秒将它们转换回 Java HashMaps(当输入他们回到Java)。