说我有一个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/
的{{1}}。这是做到这一点的方式还是有一种我失踪的非宏观方式?
答案 0 :(得分:14)
无需反射或地图。每个Java枚举都有一个静态valueOf
方法,可以按名称检索枚举值。所以:
(defn do-something-parameterized [suit]
(let [s (Suit/valueOf (name suit))] ...))
使用(name)
可以使用字符串或关键字:
(do-something-parameterized "HEARTS")
(do-something-parameterized :HEARTS)
答案 1 :(得分:1)
很久以前我问了一个类似的问题,不是关于枚举,而是关于静态类成员:How can I dynamically look up a static class member in Clojure?
答案是使用Java反射:
(defn do-something-parameterized [suit]
(let [s (.get (.getField Suits suit) nil)] (...)))
答案 2 :(得分:0)
为了提高性能,您可以创建一个包含要匹配的字符串的映射到枚举类型,例如:
(def my-enum-map {"DIAMONDS" Suits/DIAMONDS, "SPADES" Suits/SPADES...})
然后在do something函数中它看起来像:
(defn do-something-parameterized [suit]
(let [s (my-enum-map suit)] ...))
你可以在加载时使用反射(而不是手工)来构建这个地图,但在运行时,它只是一个地图查找。
答案 3 :(得分: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#)))