clojureでMapオブジェクトを相互変換してみる

JavaのMapオブジェクトとClojureのMapオブジェクトを相互変換する場合、どうしたら良いのだろうと思い、少し調べてみた。

まず、java.util.HashMapを使った場合の動きを確認してみる。
HashMapの場合、シンボルをキーにしているとClojureっぽく呼び出せる。それ以外の呼び出し方は基本エラー。

user=> (def m (java.util.HashMap.))
#'user/m
user=> (.put m "key" "value")                                                       
nil
user=> (.put m :key :value)
nil
user=> m
#<HashMap {:key=:value, key=value}>
user=> (m :key)
java.lang.ClassCastException: java.util.HashMap cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
user=> (:key m)
:value
user=> (m "key")
java.lang.ClassCastException: java.util.HashMap cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
user=> ("key" m)
java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
user=>

次にClojureのMapオブジェクトを試してみる。
ここでは、into関数を使って、HashMapからClojureのMapに変換しています。
もちろん「(def mm {:key :value, "key" "value"})」と書いても同じです。
一番最後の呼び出し方のみエラーで、それ以外は正常に動く。

user=> (def mm (into {} m))
#'user/mm
user=> mm
{:key :value, "key" "value"}
user=> (mm :key)
:value
user=> (mm "key")
"value"
user=> (:key mm)
:value
user=> ("key" mm)
java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)

ClojureのMapの方が柔軟ですね。
例えばすでにあるJavaのライブラリがHasMapを使用していて、それをClojureで使いたい場合には、一度into関数で変換してからClojureで使うと良い感じかも。

次に、ClojureのMapオブジェクトをJavaのHashMapオブジェクトに変換してみる。
一応、以下の方法で出来ていますが、ひょっとすると標準のライブラリやcontrib辺りに、変換用の関数かマクロがあるかも。
見つけられなかったので自前でやっています。

user=> (def mmm (java.util.HashMap.))
#'user/mmm
user=> (map #(.put mmm (first %) (second %)) (.entrySet mm))
(nil nil)
user=> mmm
#<HashMap {:key=:value, key=value}>