16

Clojure で使用したい Java クラスがあります。でも、Clojureマップとして使いたい。そのために必要な手順は何ですか?

コードを見てきましたIPersistentMap-- Java クラスはそれを実装する必要がありますか? それとも、プロトコルを実装する Clojure コードが必要ですか?

コードをJavaオブジェクトからマップに明示的に変換するために、いくつかのマッピングコードを書くことができることはわかっていますが、そのソリューションは労力/報酬の比率が高くなります。また、同じ状況に何度も遭遇する可能性があります。


具体例: Java で書かれたパーサーがあります。それを使用してテキストを解析し、Clojure マップにあるかのように、解析されたデータ構造の内容にアクセスしたいと思います。

(def parser (new MyParser))

(let [parse-tree (parser ... parse some text ...)]
  ((parse-tree :items) "itemid"))
4

6 に答える 6

24

関数beanが思い浮かびました:

Java オブジェクトを受け取り、その JavaBean プロパティに基づいてマップ抽象化の読み取り専用実装を返します。

サイトからの例:

user=> (import java.util.Date)
java.util.Date

user=> (def *now* (Date.))
#'user/*now*

user=> (bean *now*)
{:seconds 57, :date 13, :class java.util.Date,
 :minutes 55, :hours 17, :year 110, :timezoneOffset -330,
 :month 6, :day 2, :time 1279023957492}
于 2011-10-27T14:26:19.423 に答える
5

確かに(bean javaObject)( bean ClojureDocを参照) はうまく機能しますが、必要なプロパティとそうでないプロパティを選択することはできません。結果のマップをjson-str関数に入力すると影響があります。その場合、「...の JSON の書き方がわからない」というエラーが発生する可能性があります。

そして、本質的に JSON を受け入れる NoSQL DB (mongoDB、neo4j) ( neoconsの基礎となるものなど) を扱うとき、それが面倒だと思います。

それで、私の解決策は何ですか?

(defmacro get-map-from-object-props [object & props]
  ;->> will eval and reorder the next list starting from the end
  (->> (identity props) ;identity is here to return the 'props' seq
       ;map each property with their name as key and the java object invocation as the value
       ;the ~@ is here to unsplice the few properties
       (map (fn [prop] [(keyword (str prop)) `(.. ~object ~@(prop-symbol prop) )]))
       (into {})))

;getter is a simple function that transform a property name to its getter "name" -> "getName"
(defn prop-symbol [prop]
  (map symbol (map getter (clojure.string/split (str prop) #"\\."))))

そして、あなたはそれをそのように使うことができます(はい、関数はプロパティのチェーンを処理します)

(get-map-from-object-props javaObject property1 property2 property3.property1)

それが誰かを助けることを願っています...

于 2012-08-26T15:28:11.933 に答える
1

(インターンされた)文字列をキーとしてjava.util.HashMapを使用し、Clojureの数行で変換を行うのはどうですか?:

(into {} (java.util.HashMap. {"foo" "bar" "baz" "quux"})) ?

{"foo" "bar" "baz" "quux"}

またはキーワード付き:

(into {}
  (map
    (juxt
      #(keyword (key %))
      #(val %))
    (java.util.HashMap. {"foo" "bar" "baz" "quux"})))

{:baz "quux", :foo "bar"}
于 2011-10-27T18:55:28.400 に答える
1

Clojure キーワードは、java.lang.Map インターフェースの必要な (読み取り専用) 部分を実装するあらゆるものを検索できます。問題は、実際には clojure キーワードをキーとして使用していないため、役に立たない可能性があることです。

IPersistentMap については。あなたのパーサーはおそらくそのインターフェースに関連するものを何も実装していません。

個人的には、ストレートアップ変換関数を書きます。Clojure はそれらの多く (たとえば seq) を使用し、変換後、実際の永続的なマップを扱っていることがわかり、時々そのように振る舞うものではないことがわかります (したがって、実際に seq、keys、vals を呼び出すことができます)。など)。

あるいは;

于 2011-10-27T13:34:04.563 に答える
-2
user=> (defn parser [text]
  "{ :items { \"itemid\" 55 }}");Mock
user=> (let [parse-tree (read-string (parser "Abracadabra"))]
((parse-tree :items) "itemid"))
55
于 2011-10-27T14:26:25.263 に答える