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