简体   繁体   English

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM