我正在寻找类似doto
的东西,但不是返回x
,而是返回最后一个调用值。
例如,代替:
(.size (doto (java.util.ArrayList.)
(.add 2)
(.add 3)))
我想写:
(mydoto (java.util.ArrayList.)
(.add 2)
(.add 3)
.size)
达到这个结果的惯用方法是什么?
doto
返回它的第一个参数。 ->
和 ->>
返回计算最后一个表单的结果(在将第一个表达式串通后,请参阅 (clojure.repl/doc ->)
。宏doto
将像这样扩展您的代码:
(let [r (java.util.ArrayList.)]
(.add r 2)
(.add r 3)
r)
当你使用 .size
时,它不会影响你的数组列表,你只对方法的返回值感兴趣(不像.add
它返回一个布尔值并改变你感兴趣的 ArrayList 的状态(。
你不能像在mydoto中那样混合这些方法,因为你需要的是不同类型的返回值和输入值。如果您想将最终大小乘以 3,这将是惯用语:
(-> (doto (java.util.ArrayList.)
(.add 2)
(.add 3))
.size
(* 3))
甚至
(-> (java.util.ArrayList.)
(doto (.add 2) (.add 3))
.size
(* 3))
这些宏应该使代码更易于阅读,因此根据上下文,我会以最有意义的方式编写它们。
Clojure 宏将允许你做你想做的事,事实上它只是对现有 doto 宏的 1 个符号的更改(在 emacs 中使用 Meta-. 查看 core.clj 中的定义(。
(defmacro mydoto
"Like doto but returns the result of the last form
instead to the first argument"
[x & forms]
(let [gx (gensym)]
`(let [~gx ~x]
~@(map (fn [f]
(if (seq? f)
`(~(first f) ~gx ~@(next f))
`(~f ~gx)))
forms))))
这将允许您编写以下代码:
(mydoto (java.util.ArrayList.)
(.add 2)
(.add 3)
.size)
;; => 2
doto
编写mydoto
,如@lgrapenthin所述:
(defmacro mydoto
"Like doto but returns the result of the last form instead
of the first argument"
[& args]
`(-> (doto ~@(butlast args))
~(last args)))