4

レコード/クラスのシーケンスがあり、mapそのシーケンスをオーバーしてnew、それらのレコード/クラスのインスタンスのシーケンスを取得することを期待しています。が特別な形式であることはわかってnewいますが、この場合、Clojure が正しいことを行うことを期待していました。

しかし、これは機能しません:

(map new [SomeClass1 SomeClass2 SomeClass3])

これもそうではありません。

(map #(new %) [SomeClass1 SomeClass2 SomeClass3])

同様のコードはFactorでも機能します。

{ SomeClass1 SomeClass2 SomeClass3 } [ new ] map

Clojure でこれを行う正しい方法は何でしょうか? Class.newInstance(醜さは伴わないと思います。)

編集:

以下は機能しますが、おそらく必要以上に遅くなります。(よくわかりません。これに関する情報をいただければ幸いです。)

(map #(eval `(new ~%)) [SomeClass1 SomeClass2 SomeClass3])

また、よりエレガントなものを探しています。

4

2 に答える 2

3

特殊形式はよく...特別なので、それらはファーストクラスではなく、適切な関数のように構成されません。これはevalとマクロで解決できます。

eval を使用したソリューション:

(defn fnew [c] (eval `(new ~c))) 
hello.core> (map fnew ['Exception 'java.lang.String])
(#<Exception java.lang.Exception> "")

コンストラクターに引数を取るバージョン:

(defn fnew [c] (eval `(new ~@c))) 

hello.core> (map fnew ['(Exception) '(java.lang.String "I am a contructor argument")])
(#<Exception java.lang.Exception> "I am a contructor argument")

(map fnew [ [Exception] [(class "foo") "I am a contructor argument"]])
(#<Exception java.lang.Exception> "I am a contructor argument")

これがマクロの例です

hello.core> (defmacro newify [classes] (apply vector (for [c classes] `(new ~c))))
#'hello.core/newify

hello.core> (macroexpand '(newify [java.lang.String Exception]))
[(new java.lang.String) (new Exception)]

hello.core>  (newify [java.lang.String Exception])
["" #<Exception java.lang.Exception>]

マクロ バージョンはより効率的である可能性が高く、eval バージョンはより柔軟です。

于 2012-06-01T20:34:35.303 に答える
1

特別な形式であるためnew、ファーストクラスのように機能させるための解決策の 1 つは、次のような clojure の低レベル呼び出しを使用することです。

(map #(clojure.lang.Reflector/invokeConstructor %1 (into-array [])) [String])

これにより、リフレクションのパフォーマンスの問題が発生する可能性があるため、これよりもマクロ ベースのソリューションが優先されます。

于 2012-06-02T08:52:45.237 に答える