因子Clojure代码在Java对象中设置许多不同的字段

chr*_*ris 9 field clojure

如何在Java对象中设置许多不同字段的代码?我想要因素

(set! (. employee name) "Chris")
(set! (. employee age) 100)
(set! (. employee salary) 5000)
Run Code Online (Sandbox Code Playgroud)

(doseq [field '((name "Chris") (age 100) (salary 5000))]
  (set! (. employee (first field)) (second field)))
Run Code Online (Sandbox Code Playgroud)

但是这不起作用,因为句点是一个宏,并试图从字面上评估(第一个字段).顺便说一句,我明白设置字段不是好习惯.我需要与遗留代码互操作.

小智 8

尝试使用setter - 但是如果你没有选择并且真的需要考虑到这一点,那么像这样的宏会:

(defmacro set-all [object & fields-and-values]
  (let [obj-sym (gensym)] 
    `(let [~obj-sym ~object]
        ~@(for [[field value] (partition 2 fields-and-values)]
           `(set! (. ~obj-sym ~field)
                  ~value)))))
Run Code Online (Sandbox Code Playgroud)

如果表达式屈服对象有任何副作用,则需要gensym.

用法示例:

user> (def p (java.awt.Point.))
#'user/p
user> (set-all p x 4 y 5)
5
user> p
#<Point java.awt.Point[x=4,y=5]>
Run Code Online (Sandbox Code Playgroud)


Psy*_*llo 6

你可以试试:

(defmacro set-all! [obj m]
    `(do ~@(map (fn [e] `(set! (. ~obj ~(key e)) ~(val e))) m) ~obj))
Run Code Online (Sandbox Code Playgroud)

例:

(def a (java.awt.Point.))
(set-all! a {x 300 y 100})
Run Code Online (Sandbox Code Playgroud)

Macroexpand全:

(do (set! (. a x) 9)
    (set! (. a y) 7)
    a)
Run Code Online (Sandbox Code Playgroud)