ClojureのJava Enumへのアクセスをパラメーター化するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/7313049

  •  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#)))
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top