ClojureのJava Enumへのアクセスをパラメーター化するにはどうすればよいですか?
-
26-10-2019 - |
質問
Java Enumを持っているとします。例えば:
public enum Suits {CLUBS, DIAMONDS, HEARTS, SPADES};
通常、私はその列挙のように、Clojureで何かをすることができます:
(defn do-something []
(let [s Suits/DIAMONDS] (...)))
ただし、発信者が使用する列挙インスタンスを指定できるようにするClojure関数を書きたいと思います。
(defn do-something-parameterized [suit]
(let [s Suits/suit] (...)))
アイデアは、発信者に渡すことです "DIAMONDS"
そして、 DIAMONDS
ENUMインスタンスはバインドされます s
の中に let
.
私は持っていることができます cond
パラメーターと一致しますが、それは必要以上にぎこちないようです。マクロを使用して構築できると思います Suits/
に追加 suit
. 。これはそれを行う方法ですか、それとも私が欠けている非マクロの方法はありますか?
解決
反射やマップは必要ありません。すべてのJava Enumには静的があります valueOf
名前で列挙値を取得する方法。そう:
(defn do-something-parameterized [suit]
(let [s (Suit/valueOf (name suit))] ...))
使用 (name)
文字列またはキーワードのいずれかを使用できます。
(do-something-parameterized "HEARTS")
(do-something-parameterized :HEARTS)
他のヒント
私は、列挙に関してではなく、一般的な静的クラスのメンバーに関しては、かなり前に同様の質問をしました。 Clojureの静的クラスメンバーを動的に検索するにはどうすればよいですか?
答えは、Java Reflectionを使用することでした:
(defn do-something-parameterized [suit]
(let [s (.get (.getField Suits suit) nil)] (...)))
パフォーマンスを改善するには、列挙タイプに合わせたい文字列でマップを作成できます。たとえば、次のようになります。
(def my-enum-map {"DIAMONDS" Suits/DIAMONDS, "SPADES" Suits/SPADES...})
その後、何か関数を実行すると、次のようになります。
(defn do-something-parameterized [suit]
(let [s (my-enum-map suit)] ...))
また、ロード時間中にリフレクションを使用して(手ではなく)このマップを構築できますが、ランタイム中には、単なるマップルックアップです。
(defmacro def-enum-alias
"Make name reference enum.
(def-enum-alias enum-name MyClass$MyEnum)
(enum-name Foo)
second desugars to MyClass$MyEnum/Foo"
[name enum]
`(defmacro ~name
~(str "automatically generated alias for enum "
enum)
[member#]
(symbol-munge (quote ~enum) "/" member#)))
所属していません StackOverflow