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为你提供像do
和do
事情.
特别是您可以轻松处理Java代码。
assoc
只能在Clojure数据结构上工作,因为很多工作都花费在创建新的(不可变的)副本上,而且只需稍作修改即可。 Java HashMaps并不打算以相同的方式工作。 每次进行更改时都必须克隆它们,这可能会很昂贵。
如果你真的想摆脱Java的突变 - 土地(例如,也许你保持这些哈希矩阵很长一段时间,并不希望Java在所有地方调用,或者你需要通过print
和read
序列化它们,或者您希望使用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