Pergunta

Say I have a Java enum. For example:

public enum Suits {CLUBS, DIAMONDS, HEARTS, SPADES};

Normally, I can do something in clojure with that enum like so:

(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:

(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.

I could have a cond match against the parameter but that seems clunkier than necessary. I suppose I could also use a macro to construct Suits/ added to suit. Is this the way to do it or is there a non-macro way that I'm missing?

Foi útil?

Solução

No need for reflection or maps. Every Java enum has a static valueOf method that retrieves an enum value by name. So:

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

Using (name) allows either strings or keywords to be used:

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

Outras dicas

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?

The answer was to use Java reflection:

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

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:

 (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.

(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#)))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top