在clojure中,如何调用x的所有方法然后返回最后一个表单执行的值?

vie*_*bel 3 clojure

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

例如,而不是:

(.size (doto (java.util.ArrayList.) 
             (.add 2)
             (.add 3)))
Run Code Online (Sandbox Code Playgroud)

我想写:

(mydoto (java.util.ArrayList.) 
             (.add 2)
             (.add 3)
             .size)
Run Code Online (Sandbox Code Playgroud)

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

Leo*_*hin 11

doto返回它的第一个参数.->->>返回评估最后一个表单的结果(在线程化第一个表达式之后,请参阅(clojure.repl/doc ->).宏doto将扩展您的代码,如下所示:

(let [r (java.util.ArrayList.)]
  (.add r 2)
  (.add r 3)
  r)
Run Code Online (Sandbox Code Playgroud)

在使用时.size,它不会影响您的数组列表,您只对该方法的返回值感兴趣(与使用.add它返回一个布尔值并更改您感兴趣的ArrayList的状态不同).

你不能像mydoto那样混合这些方法,因为你需要的是不同类型的返回值和输入值.如果你想将最终大小乘以3,这将是惯用的:

(-> (doto (java.util.ArrayList.) 
          (.add 2)
          (.add 3))
    .size
    (* 3))
Run Code Online (Sandbox Code Playgroud)

甚至

(-> (java.util.ArrayList.)
    (doto (.add 2) (.add 3))
    .size
    (* 3))
Run Code Online (Sandbox Code Playgroud)

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


use*_*049 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))))
Run Code Online (Sandbox Code Playgroud)

这将允许您编写以下代码:

(mydoto (java.util.ArrayList.) 
         (.add 2)
         (.add 3)
         .size)
;; => 2
Run Code Online (Sandbox Code Playgroud)

  • 编写这样的宏来实现 OP 想要的功能并不符合习惯,只是混淆了他使用它的源代码。它也可以写成单行重用现有代码:(defmacro my-doto [& args]`( -> (doto ~@(butlast args)) ~(last args))) (4认同)