2011-09-05 53 views
11

假設我有一個Java枚舉。例如:如何在clojure中參數化訪問Java枚舉?

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枚舉實例得到了勢必。

我可以有一個cond匹配的參數,但似乎比必要的更笨重。我想我也可以使用宏來構造Suits/添加到suit。這是做到這一點的方式,還是有一種我不知道的非宏觀方式?

回答

14

無需反射或地圖。每個Java枚舉都有一個靜態的valueOf方法,該方法通過名稱檢索枚舉值。所以:

(defn do-something-parameterized [suit] 
    (let [s (Suit/valueOf (name suit))] ...)) 

使用(name)允許使用字符串或關鍵字:

(do-something-parameterized "HEARTS") 
(do-something-parameterized :HEARTS) 
+0

那麼明顯,戴夫。我很尷尬,我忘記了這一點。 – stand

+0

啊,好多了! –

0

爲了提高性能,你可以用你想要匹配的字符串創建一個映射到枚舉類型,例如:

(def my-enum-map {"DIAMONDS" Suits/DIAMONDS, "SPADES" Suits/SPADES...}) 

然後在做某事的功能它會看起來li柯:

(defn do-something-parameterized [suit] 
    (let [s (my-enum-map suit)] ...)) 

而且你可以在加載時使用反射(而不是手)建立這個地圖,但運行時,它只是一個地圖查找期間。

0
(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#)))