我正在寻找doto
之类的内容,但我想返回最后一个调用值,而不是返回x
。
例如,而不是:
(.size (doto (java.util.ArrayList.)
(.add 2)
(.add 3)))
我想写:
(mydoto (java.util.ArrayList.)
(.add 2)
(.add 3)
.size)
实现这一结果的惯用方法是什么?
答案 0 :(得分:11)
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))
这些宏应该使代码更容易阅读,这取决于我以最有意义的方式编写它们的上下文。
答案 1 :(得分: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
答案 2 :(得分:1)
如@lgrapenthin所述,可以使用mydoto
撰写doto
:
(defmacro mydoto
"Like doto but returns the result of the last form instead
of the first argument"
[& args]
`(-> (doto ~@(butlast args))
~(last args)))