13

假设我有一个 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枚举实例绑定slet.

我可以cond对参数进行匹配,但这似乎比必要的要笨重。我想我也可以使用宏来构造Suits/添加到suit. 这是这样做的方式还是我缺少一种非宏观方式?

4

4 回答 4

14

无需反射或地图。每个 Java 枚举都有一个valueOf按名称检索枚举值的静态方法。所以:

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

Using(name)允许使用字符串或关键字:

(do-something-parameterized "HEARTS")
(do-something-parameterized :HEARTS)
于 2011-09-06T00:48:21.340 回答
1

很久以前我问过一个类似的问题,不是关于枚举,而是关于一般的静态类成员:如何在 Clojure 中动态查找静态类成员?

答案是使用 Java 反射:

(defn do-something-parameterized [suit]
  (let [s (.get (.getField Suits suit) nil)] (...)))
于 2011-09-05T22:48:41.197 回答
0

为了提高性能,您可以使用要匹配的字符串创建一个映射到枚举类型,例如:

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

然后在 do something 函数中它看起来像:

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

您可以在加载时使用反射(而不是手动)构建此映射,但在运行时,它只是一个映射查找。

于 2011-09-05T22:59:59.203 回答
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#)))
于 2013-07-21T20:43:59.103 回答