我想做一些叫做ds的东西
(let [a 2]
(ds a))
Run Code Online (Sandbox Code Playgroud)
- >
"a->2"
Run Code Online (Sandbox Code Playgroud)
和
(let [a 1 b 2 c 3]
(ds a b c))
Run Code Online (Sandbox Code Playgroud)
- >
"a->1, b->2, c->3"
Run Code Online (Sandbox Code Playgroud)
到目前为止,我已经达到了:
(defmacro ds3 [a b c]
`(clojure.string/join ", "
[(str '~a "->" ~a)
(str '~b "->" ~b)
(str '~c "->" ~c)]))
Run Code Online (Sandbox Code Playgroud)
这似乎工作:
(let [ a 1 b 2 c 3]
(ds3 a b c)) ; "1->1, 2->2, 3->3"
Run Code Online (Sandbox Code Playgroud)
显然我可以定义ds1 ds2 ds3等...但是我想知道如何使它成为可变参数?
Ank*_*kur 10
干得好:
(defmacro ds [& symbols]
`(clojure.string/join ", "
~(into []
(map (fn [s] `(str ~(name s) "->" ~s)) symbols))))
Run Code Online (Sandbox Code Playgroud)
Ankur的答案可能是最实用的,但是他将很多工作推迟到运行时,这可以在宏扩展时完成.这是一个非常有用的练习,可以很好地演示功能宏,看看你在编译时可以做多少工作:
(defmacro ds [& args]
`(str ~(str (name (first args)) "->")
~(first args)
~@(for [arg (rest args)
clause [(str ", " (name arg) "->") arg]]
clause)))
(macroexpand-1 '(ds a b c))
=> (clojure.core/str "a->" a ", b->" b ", c->" c)
Run Code Online (Sandbox Code Playgroud)
这样可以避免在运行时构建任何临时对象,并且可以实现绝对最少的字符串连接数.