Как я могу параметризовать доступ к перечислению Java в clojure?
Скажем, у меня есть перечисление Java. Например:
public enum Suits {CLUBS, DIAMONDS, HEARTS, SPADES};
Обычно я могу сделать что-то в clojure с таким перечислением, как это:
(defn do-something []
(let [s Suits/DIAMONDS] (...)))
Но я хочу написать функцию clojure, которая позволяет вызывающему указать, какой экземпляр перечисления использовать:
(defn do-something-parameterized [suit]
(let [s Suits/suit] (...)))
Идея состоит в том, чтобы позволить вызывающему абоненту проходить в "DIAMONDS"
и иметь экземпляр enum DIAMONDS
, связанный с s
в let
.
Я мог бы сопоставить cond
с параметром, но это кажется неуклюжим, чем необходимо. Я полагаю, что я мог бы также использовать макрос для построения Suits/
, добавленного в suit
. Это способ сделать это или есть не-макропоток, который мне не хватает?
Ответы
Ответ 1
Не нужно отражать или отображать карты. Каждое перечисление Java имеет статический метод valueOf
, который извлекает значение перечисления по имени. Итак:
(defn do-something-parameterized [suit]
(let [s (Suit/valueOf (name suit))] ...))
Использование (name)
позволяет использовать либо строки, либо ключевые слова:
(do-something-parameterized "HEARTS")
(do-something-parameterized :HEARTS)
Ответ 2
Я задал подобный вопрос давно, а не о перечислениях, но статических членах класса вообще: Как я могу динамически искать статический член класса в Clojure?
Ответ заключался в использовании отражения Java:
(defn do-something-parameterized [suit]
(let [s (.get (.getField Suits suit) nil)] (...)))
Ответ 3
Чтобы повысить производительность, вы можете создать карту со строкой, которую вы хотите сопоставить, с типом перечисления, например:
(def my-enum-map {"DIAMONDS" Suits/DIAMONDS, "SPADES" Suits/SPADES...})
Затем в функции do что-то будет выглядеть:
(defn do-something-parameterized [suit]
(let [s (my-enum-map suit)] ...))
И вы можете построить эту карту во время загрузки с использованием отражения (а не вручную), но во время выполнения это просто просмотр карты.
Ответ 4
(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#)))