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