Clojure:以惯用的Clojure方式使用java.util.HashMap

我有一个java.util.HashMap对象m (从调用到Java代码的返回值),我想用一个额外的键 - 值对获得一个新的映射。

如果m是Clojure地图,我可以使用:

(assoc m "key" "value")

但在HashMap上试试这样做:

java.lang.ClassCastException:java.util.HashMap不能转换为clojure.lang.Associative

seq没有运气:

(assoc (seq m) "key" "value")

java.lang.ClassCastException:clojure.lang.IteratorSeq不能转换为clojure.lang.Associative

我设法做到这一点的唯一方法是使用HashMap自己的put ,但是返回void所以我必须显式返回m

(do (. m put "key" "value") m)

这不是惯用的Clojure代码,加上我正在修改m而不是创建一个新的地图。

如何在更多Clojure-ish方式下使用HashMap


Clojure使java集合可以被seq-able,所以你可以直接在java.util.HashMap上使用Clojure序列函数。

但是,期望一个clojure.lang.Associative,所以你必须首先将java.util.HashMap转换为:

(assoc (zipmap (.keySet m) (.values m)) "key" "value")

编辑:更简单的解决方案:

(assoc (into {} m) "key" "value")

如果您正在与Java代码进行交互,那么您可能必须咬紧牙关,用Java的方式来使用.put 。 这不一定是一种致命的罪过; Clojure为你提供像dodo事情. 特别是您可以轻松处理Java代码。

assoc只能在Clojure数据结构上工作,因为很多工作都花费在创建新的(不可变的)副本上,而且只需稍作修改即可。 Java HashMaps并不打算以相同的方式工作。 每次进行更改时都必须克隆它们,这可能会很昂贵。

如果你真的想摆脱Java的突变 - 土地(例如,也许你保持这些哈希矩阵很长一段时间,并不希望Java在所有地方调用,或者你需要通过printread序列化它们,或者您希望使用Clojure STM以线程安全的方式使用它们),因为您可以轻松地在Java HashMaps和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)。


  • 以传统方式使用java哈希映射完全可以。
    (do (. m put "key" "value") m)
    This is not idiomatic Clojure code, plus I'm modifying m instead of creating a new map.

    您正在修改真正意图修改的数据结构。 Java的哈希映射缺少允许有效复制Clojures映射的结构共享。 这样做的一般惯用方法是使用java-interop函数以典型的java方式处理java结构,或者干净地将它们转换为Clojure结构并以功能性Clojure方式处理它们。 除非它使生活变得更容易并且导致更好的代码; 那么所有投注都关闭。

    链接地址: http://www.djcxy.com/p/66869.html

    上一篇: Clojure: working with a java.util.HashMap in an idiomatic Clojure fashion

    下一篇: What is the best way to do GUIs in Clojure?