问题 如何在clojure中参数化对Java枚举的访问?


说我有一个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 枚举实例绑定到 s 在里面 let

我可以有一个 cond 匹配参数,但似乎比必要的笨拙。我想我也可以使用宏来构建 Suits/ 添加到 suit。这是做到这一点的方式还是有一种我失踪的非宏观方式?


12481
2017-09-05 21:52


起源



答案:


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

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

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

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

14
2017-09-06 00:48



很明显,戴夫。我很尴尬,我忘了这件事。 - stand
啊,好多了! - Christian Berg


答案:


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

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

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

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

14
2017-09-06 00:48



很明显,戴夫。我很尴尬,我忘了这件事。 - stand
啊,好多了! - Christian Berg


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

答案是使用Java反射:

(defn do-something-parameterized [suit]
  (let [s (.get (.getField Suits suit) nil)] (...)))

1
2017-09-05 22:48





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

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

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

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

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


0
2017-09-05 22:59





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

0
2017-07-21 20:43