Как я могу параметризировать доступ к Java enum в Clojure?

StackOverflow https://stackoverflow.com/questions/7313049

  •  26-10-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

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

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

Это было полезно?

Решение

Нет необходимости в отражении или картах. У каждого Java enum есть статический valueOf Метод, который получает значение перечисления по имени. Так:

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

С использованием (name) Позволяет использовать строки или ключевые слова:

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

Другие советы

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

Ответ состоял в том, чтобы использовать Java Reflection:

(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#)))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top