[英]How can I parameterize access to a Java enum in clojure?
Say I have a Java enum. 说我有一个Java枚举。 For example:
例如:
public enum Suits {CLUBS, DIAMONDS, HEARTS, SPADES};
Normally, I can do something in clojure with that enum like so: 通常情况下,我可以用这样的枚举做一些clojure:
(defn do-something []
(let [s Suits/DIAMONDS] (...)))
But, I want to write a clojure function that allows the caller to specify which enum instance to use: 但是,我想编写一个clojure函数,允许调用者指定要使用的枚举实例:
(defn do-something-parameterized [suit]
(let [s Suits/suit] (...)))
The idea is to let a caller pass in "DIAMONDS"
and have the DIAMONDS
enum instance get bound to s
in the let
. 这个想法是让一个调用者传入
"DIAMONDS"
并让DIAMONDS
枚举实例绑定到let
s
。
I could have a cond
match against the parameter but that seems clunkier than necessary. 我可以对参数进行
cond
匹配,但这似乎比必要的更笨拙。 I suppose I could also use a macro to construct Suits/
added to suit
. 我想我还可以使用宏来构造
Suits/
加suit
。 Is this the way to do it or is there a non-macro way that I'm missing? 这是做到这一点的方式还是有一种我失踪的非宏观方式?
No need for reflection or maps. 无需反射或地图。 Every Java enum has a static
valueOf
method that retrieves an enum value by name. 每个Java枚举都有一个静态
valueOf
方法,该方法按名称检索枚举值。 So: 所以:
(defn do-something-parameterized [suit]
(let [s (Suit/valueOf (name suit))] ...))
Using (name)
allows either strings or keywords to be used: 使用
(name)
允许使用字符串或关键字:
(do-something-parameterized "HEARTS")
(do-something-parameterized :HEARTS)
I asked a similar question a long while ago, not regarding enums but static class members in general: How can I dynamically look up a static class member in Clojure? 很久以前我问了一个类似的问题,不是关于枚举而是关于静态类成员: 我怎样才能在Clojure中动态查找静态类成员?
The answer was to use Java reflection: 答案是使用Java反射:
(defn do-something-parameterized [suit]
(let [s (.get (.getField Suits suit) nil)] (...)))
(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#)))
To improve performance, you could create a map with the string that you want to match, to the enum type, for example: 要提高性能,您可以创建一个包含要匹配的字符串的映射到枚举类型,例如:
(def my-enum-map {"DIAMONDS" Suits/DIAMONDS, "SPADES" Suits/SPADES...})
Then in the do something function it would look like: 然后在do something函数中它看起来像:
(defn do-something-parameterized [suit]
(let [s (my-enum-map suit)] ...))
And you can build this map during load time using reflection (instead of by hand), but during runtime, its just a map lookup. 您可以在加载时使用反射(而不是手动)构建此映射,但在运行时,它只是一个地图查找。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.