Динамические вызовы метода в макросе Clojure?

Нет, потому что платформа не знает, как сравнить содержание Ваших списков.

Взглянули на это:

http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx

14
задан npad 10 November 2009 в 23:16
поделиться

4 ответа

В макросах хорошо то, что вам не нужно копаться в классах или в чем-то подобном. Вам просто нужно написать код , который генерирует правильные s-выражения .

Сначала функция для генерации s-выражения, например (. SetName 42)

(defn make-call [name val]
  (list (symbol (str ".set" name) val)))

, затем макрос для генерации выражений и вставьте ( ~ @ ) их в выражение doto .

(defmacro map-set [class things]
  `(doto ~class ~@(map make-call things))

Поскольку это макрос, ему никогда не нужно знать, к какому классу относится объект, к которому он вызывается, или даже класс, в котором он будет используется существует.

19
ответ дан 1 December 2019 в 09:01
поделиться

Кто-то (я полагаю, Артур Ульфельдт) опубликовал ответ, который был почти правильным, но теперь он был удален. Пожалуйста, примите его вместо моего, если он отправит сообщение снова. (Или примите pmf.) Это рабочая версия:

(defmacro set-all [obj m]
  `(doto ~obj ~@(map (fn [[k v]]
                       (list (symbol (str ".set" k)) v))
                     m)))

user> (macroexpand-1 '(set-all (java.util.Date.) {"Month" 0 "Date" 1 "Year" 2009}))
(clojure.core/doto (java.util.Date.) (.setMonth 0) (.setDate 1) (.setYear 2009))

user> (set-all (java.util.Date.) {"Month" 0 "Date" 1 "Year" 2009})
#<Date Fri Jan 01 14:15:51 PST 3909>
4
ответ дан 1 December 2019 в 09:01
поделиться

Вы должны укусить пулю и использовать clojure.lang.Reflector / invokeInstanceMethod следующим образом:

(defn do-stuff [obj m]
  (doseq [[k v] m]
    (let [method-name (str "set" k)]
      (clojure.lang.Reflector/invokeInstanceMethod
        obj
        method-name
        (into-array Object [v]))))
   obj)

(do-stuff (java.util.Date.) {"Month" 2}) ; use it

Нет необходимости в макросе (насколько я знаю, макрос тоже не позволил бы обойти отражение, по крайней мере, в общем случае)

2
ответ дан 1 December 2019 в 09:01
поделиться

Пожалуйста, не создавайте s-выражения с списком для макросов. Это серьезно повредит гигиене макроса. Совершить ошибку очень легко, и ее трудно отследить. Пожалуйста, всегда используйте синтаксические кавычки! Хотя в данном случае это не проблема, хорошо бы иметь привычку использовать только синтаксические кавычки!

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

(defmacro configure
  [object options]
  `(doto ~object
     ~@(map (fn [[property value]]
              (let [property (name property)
                    setter   (str ".set"
                                  (.toUpperCase (subs property 0 1))
                                  (subs property 1))]
                `(~(symbol setter) ~value)))
            options)))

Это можно использовать как:

user=> (macroexpand-1 '(configure (MyClass.) {:username "fred" :password "wilma"}))
(clojure.core/doto (MyClass.) (.setUsername "fred") (.setPassword "wilma"))
5
ответ дан 1 December 2019 в 09:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: