7

Clojure バインディングで Java ライブラリをラップしようとしています。Java ライブラリの 1 つの特定のクラスは、静的な最終定数の束を定義します。次に例を示します。

class Foo {
    public static final int BAR = 0;
    public static final int SOME_CONSTANT = 1;
    ...
}

defクラスを調べて、これらの定数をそれぞれ明示的に -ing せずに Clojure 名前空間に取り込むことができるのではないかと考えました。

たとえば、次のように明示的に接続する代わりに、次のようにします。

(def foo-bar Foo/BAR)
(def foo-some-constant Foo/SOME_CONSTANT)

モジュールが読み込まれると、クラスを調べてFoo動的に接続しfoo-barfoo-some-constantClojure 名前空間に入れることができます。

これを行う理由は 2 つあります。

FooA)クラスに追加された新しい定数を自動的に取り込みます。言い換えれば、Java インターフェースが新しい定数を追加した場合、Clojure ラッパーを変更する必要はありません。

B)定数がよりClojure風の命名規則に従うことを保証できます

私はこれを行うことに自信があるわけではありませんが、Clojure/Java の相互運用に関する知識を広げるために尋ねるのは良い質問のようです。

ありがとう

4

3 に答える 3

3

残念ながら、マクロclojure.contrib.import-staticでは、すべての静的最終フィールドをインポートできません。インポートするフィールドのリストを提供する必要があります。

このマクロは、import-staticの慣用的なラッパーです。

(ns stackoverflow
  (:use clojure.contrib.import-static)
  (:import (java.lang.reflect Modifier)))

(defmacro import-static-fields
  "Imports all static final fields of the class as (private) symbols
  in the current namespace.

  Example: 
      user> (import-static-fields java.lang.Integer)
      #'user/TYPE
      user> MAX_VALUE
      2147483647

  Note: The class name must be fully qualified, even if it has already
  been imported."
  [class]
  (let [final-static-field? (fn [field]
                  (let [modifiers (.getModifiers field)]
                (and (Modifier/isStatic modifiers) (Modifier/isFinal modifiers))))
    static-fields (map #(.getName %)
               (filter
                final-static-field?
                (.. Class (forName (str class)) getFields)))]
    `(import-static ~class ~@static-fields)))
于 2010-04-04T12:14:51.103 に答える
2

(この回答には 2 つの実用的なソリューションが含まれています。1 つは私の最初のアイデアに基づくものでintern、もう 1 つは を使用するという danlei の提案に基づいていますc.c.import-static。後でこれをクリーンアップする必要があると思いますが、今はそれ以上の時間を費やすことはできません。 ...)

静的フィールドを抽出するには:

(filter #(bit-and java.lang.reflect.Modifier/STATIC (.getModifiers %))
        (.getFields YourClass))

#(intern *ns* (str "a-prefix-" (.getName %)) (.get YourClass nil))次に、そのシーケンス全体にマップして値を取得します...このビットはテストされていないことに注意してください。特にnil.get; 試してjava.lang.Fieldみて、クラスで何が機能するかを確認してください。

更新 2:

わかりました、実際には、internベースド アプローチは可読性に関してそれほど悪くはありません。

user> (map #(intern *ns* (symbol (str "integer-" (.getName %))) (.get % java.lang.Integer))
           (filter #(bit-and java.lang.reflect.Modifier/STATIC
                             (.getModifiers %))
                   (.getFields java.lang.Integer)))
(#'user/integer-MIN_VALUE #'user/integer-MAX_VALUE #'user/integer-TYPE #'user/integer-SIZE)
user> integer-MIN_VALUE
-2147483648
user> integer-MAX_VALUE
2147483647
user> integer-TYPE
int
user> integer-SIZE
32

更新: (代替ソリューションとして最初の更新をそのままにしておきます)

上記の danlei の知識を組み合わせるclojure.contribと、次の結果が得られます。

user> (map #(eval `(import-static java.lang.Integer ~(symbol (.getName %))))
           (filter #(bit-and java.lang.reflect.Modifier/STATIC
                             (.getModifiers %))
                   (.getFields java.lang.Integer)))
(#'user/MIN_VALUE #'user/MAX_VALUE #'user/TYPE #'user/SIZE)
user> MIN_VALUE
-2147483648
user> MAX_VALUE
2147483647
user> TYPE
int
user> SIZE
32

それは使用しevalます...まあ、それは、「パフォーマンスを殺す」ことはほとんどなく、実際にはかなり読みやすいですが、これは精巧な表現を使用してinternもそうではないかもしれません. (実際にはそれほど悪くはありません... :-))ただし、 上記のスケッチが何らかの形で間違っていることが判明した場合、少なくとも の実装により適切なアイデアが得られます。internimport-static

于 2010-04-03T19:29:51.940 に答える
1

試したことはありませんが、clojure.contrib.import-static でできるかもしれません。

確認したところ: import-static を使用する場合はメソッド/フィールドに名前を付ける必要がありますが、関連する回答を探している人に役立つ可能性があるため、この回答をここに残しておきます。

于 2010-04-03T19:30:49.503 に答える