вызов специальной формы `set!` в макросе clojure - PullRequest
0 голосов
/ 14 января 2019

Учитывая экземпляр Java obj и имя члена (строка) "Foo", а также карту conf, я пытаюсь сгенерировать код Clojure, который будет выглядеть следующим образом:

(if (get conf "Foo")
    (set! (.Foo obj) (get conf "foo")
    obj)

А также, если я знаю, что "SomeEnum" - это имя перечисления Java, код такой:

(if (get conf "SomeEnum")
    (set! (.someEnum obj)(Enum/valueOf SomeEnum (get conf "SomeEnum")))
    obj)

Вот что я придумал:

(defmacro set-java [obj conf obj-name]
  `(if (get ~conf ~obj-name)
     (set! (. ~obj ~(symbol obj-name)) (get ~conf ~obj-name))
     ~obj))

(defn lowercase-first [s]
  (apply str (Character/toLowerCase (first s)) (rest s)))

(defmacro set-java-enum [obj conf obj-name]
  `(if (get ~conf ~obj-name)
     (set! (. ~obj ~(symbol (lowercase-first obj-name)))
           (Enum/valueOf ~(symbol obj-name) (get ~conf ~obj-name)))
     ~obj))

Тестирование с macroexpand, кажется, дает правильный результат, но после попытки:

(defn ^Policy map->policy [conf]
  (-> (Policy.)
      (set-java-enum conf "CommitLevel")
      (set-java conf "durableDelete")
      (set-java conf "expiration")
      (set-java conf "generation")
      (set-java-enum conf "GenerationPolicy")
      (set-java-enum conf "RecordExistsAction")
      (set-java conf "respondAllOps")))

У меня странный бесконечный цикл предупреждений об отражениях.

--- редактировать ---

после долгого времени с этим я отказался от потоков (->) и закончил:

(defmacro set-java [obj conf obj-name]
  `(when (get ~conf ~obj-name)
     (set! (. ~obj ~(symbol obj-name)) (get ~conf ~obj-name))))

(defn lowercase-first [s]
  (apply str (Character/toLowerCase ^Character (first s)) (rest s)))

(defmacro set-java-enum [obj conf obj-name]
  `(when (get ~conf ~obj-name)
     (set! (. ~obj ~(symbol (lowercase-first obj-name)))
           (Enum/valueOf ~(symbol obj-name) (get ~conf ~obj-name)))))

(defn map->write-policy [conf]
  (let [wp (WritePolicy. (map->policy conf))]
    (set-java-enum wp conf "CommitLevel")
    (set-java wp conf "durableDelete")
    ;; more non threaded object manipulation
    wp))

Так что я до сих пор не уверен, о чем был бесконечный цикл предупреждения об отражении, но, надеюсь, это также полезно и может быть улучшено в дальнейшем.

1 Ответ

0 голосов
/ 14 января 2019

Я думаю, это связано с тем, что вы интерполировали ~obj несколько раз в каждом макросе. Ваш "цикл" на самом деле бесконечен, или это просто ~ 128 или ~ 256 шагов?

В любом случае, исправление для этой конкретной проблемы (независимо от того, является ли это коренной причиной описываемой вами проблемы) - заключить форму в (let [obj# ~obj] ...) и затем обратиться к obj# ниже, поэтому аргумент только интерполируется один раз.

Вы можете (должны!) Сделать это также с conf и obj-name, но они, вероятно, не вызывают активных проблем, по крайней мере с предоставленным вами кодом использования.

...