5

我正在寻找类似doto但不是返回的东西x,我想返回最后一个调用值。

例如,而不是:

(.size (doto (java.util.ArrayList.) 
             (.add 2)
             (.add 3)))

我想写:

(mydoto (java.util.ArrayList.) 
             (.add 2)
             (.add 3)
             .size)

实现此结果的惯用方法是什么?

4

3 回答 3

13

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))

这些宏应该使代码更易于阅读,因此根据上下文我会以最有意义的方式编写它们。

于 2013-08-04T11:37:46.663 回答
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
于 2013-08-04T13:17:30.297 回答
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)))
于 2013-08-05T06:11:49.750 回答