2011-09-05 55 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#)))