Как я могу параметризовать доступ к перечислению Java в clojure? - PullRequest
11 голосов
/ 06 сентября 2011

Скажем, у меня есть перечисление Java. Например:

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

Обычно я могу сделать что-то в тайне с этим перечислением, например:

(defn do-something []
   (let [s Suits/DIAMONDS] (...)))

Но я хочу написать функцию clojure, которая позволит вызывающей стороне указать, какой экземпляр enum использовать:

(defn do-something-parameterized [suit]
   (let [s  Suits/suit] (...)))

Идея состоит в том, чтобы позволить вызывающему пройти в "DIAMONDS" и иметь экземпляр enum DIAMONDS, связанный с s в let.

Я мог бы сопоставить cond с параметром, но это кажется более грубым, чем необходимо. Я полагаю, я мог бы также использовать макрос для создания Suits/ добавленного к suit. Это способ сделать это или есть немакро-способ, который мне не хватает?

Ответы [ 4 ]

14 голосов
/ 06 сентября 2011

Нет необходимости в отражении или картах.Каждое перечисление Java имеет статический метод valueOf, который получает значение перечисления по имени.Итак:

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

Использование (name) позволяет использовать либо строки, либо ключевые слова:

(do-something-parameterized "HEARTS")
(do-something-parameterized :HEARTS)
1 голос
/ 06 сентября 2011

Я задал похожий вопрос давно, не в отношении перечислений, а в целом статических членов класса: Как я могу динамически искать статический член класса в Clojure?

Ответ должен был использовать отражение Java:

(defn do-something-parameterized [suit]
  (let [s (.get (.getField Suits suit) nil)] (...)))
0 голосов
/ 22 июля 2013
(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#)))
0 голосов
/ 06 сентября 2011

Для повышения производительности вы можете создать карту со строкой, которую вы хотите сопоставить, с типом перечисления, например:

 (def my-enum-map {"DIAMONDS" Suits/DIAMONDS, "SPADES" Suits/SPADES...})

Тогда в функции "сделать что-то" это будет выглядеть так:

 (defn do-something-parameterized [suit]
    (let [s (my-enum-map suit)] ...))

И вы можете построить эту карту во время загрузки, используя отражение (а не вручную), но во время выполнения это просто поиск по карте.

...