Нет, потому что платформа не знает, как сравнить содержание Ваших списков.
Взглянули на это:
http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx
В макросах хорошо то, что вам не нужно копаться в классах или в чем-то подобном. Вам просто нужно написать код , который генерирует правильные 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))
Поскольку это макрос, ему никогда не нужно знать, к какому классу относится объект, к которому он вызывается, или даже класс, в котором он будет используется существует.
Кто-то (я полагаю, Артур Ульфельдт) опубликовал ответ, который был почти правильным, но теперь он был удален. Пожалуйста, примите его вместо моего, если он отправит сообщение снова. (Или примите 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>
Вы должны укусить пулю и использовать 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
Нет необходимости в макросе (насколько я знаю, макрос тоже не позволил бы обойти отражение, по крайней мере, в общем случае)
Пожалуйста, не создавайте 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"))