2

我是clojure的新手,如果我还没有使用正确的术语,请原谅。我正在寻找一种方法,以最惯用的方式执行以下操作:

我有一个函数可以将任何给定数量的地图合并为一个,我们称之为merge-maps

现在我需要一个调用第一个函数的第二个函数,然后调用一个带有结果的静态 void java 函数,然后返回完全相同的结果。我得到了前两件事,但我没有做第三件事。由于静态 void 方法评估为零,我必须以某种方式返回该值,但我不明白如何:

(defn my-funky-function [& ms]
   (def merged (merge-maps ms))
   (SomeJavaClass/someStaticVoidMethod merged, "some", "other", "stuff")
   ;????? <- how do I "return" merged from here?)
)
4

2 回答 2

1

不需要函数,也不要def在函数内部使用,除非您明确打算“创建和实习全局变量”(文档字符串def)。合并地图可以用merge.

(doto (merge ms) (SomeJavaClass/someStaticVoidMethod "some" "other" "stuff"))

编辑:因为关于 def 的正确使用,我的回答可能会被误解(请参阅 Leonids 评论):在函数内部使用 def 绝不是一个好主意。我从文档字符串中引用来暗示使用 def 的全局效果,你当然不想在你的函数中使用它。

EDIT2:这里对上面的行进行了更多解释: doto 总是返回它的第一个参数。如果它是可变的并且它之后的表达式修改它作为副作用,则返回修改后的版本。但是,如果您只想调用(可能)具有不修改第一个参数的副作用的静态方法,则使用 doto 是正确的,因为您可以依赖映射的不变性。

由于您要求采用通用的惯用方法并希望在您的静态方法(或具有副作用的函数)不期望您期望的返回值作为第一个参数时解决类似的问题,因此您始终可以这样做:

(doto (merge ms) (#(SomeJavaClass/someStaticMethod "Some" "other" "stuff" %)))

现在,如果出于任何原因您需要确保静态方法永远不会修改参数(如果它是可变的),那么使用 let 块没有帮助。这是因为在 let-block 中,您将符号绑定到可变事物,并且您不会从符号中获取它的旧值。您需要事先创建旧值的副本,通常是通过调用它的构造函数并创建它的新实例。

repl 中的示例:

(let [a (into-array [4 3 2 1]]
  (java.util.Arrays/sort a)
  a)
(first *1)
=> 1

;; now how to return the original thiing
(let [a (into-array [4 3 2 1])
      a-copy (aclone a)]
  (java.util.Arrays/sort a)
  ;; do some other ops on a, maybe invoke side-effects
  a-copy)
(first *1)
=> 4

因此,如果第一个 let-block 产生了您想要的结果,那么 let-block 可以替换为 doto ,它是一个辅助宏,除了为您创建该 let-block 之外什么都不做。

(doto (into-array [4 3 2 1]) java.util.Arrays/sort)
(first *1)
=> 1
(macroexpand '(doto (into-array [4 3 2 1]) java.util.Arrays/sort))
=> (let* [G__7326 (into-array [4 3 2 1])] (java.util.Arrays/sort G__7326) G__7326)

由于您没有对合并地图“做任何事情”,因此名称“doto”可能会有点误导,但希望我能说服您节省几行冗余代码。

于 2013-07-25T15:20:30.407 回答
1

像这样

(defn my-funky-function [& ms]
   (def merged (merge-maps ms))
   (SomeJavaClass/someStaticVoidMethod merged, "some", "other", "stuff")
   merged)

注意:您应该使用let绑定而不是使用def.

(defn my-funky-function [& ms]
   (let [merged (merge-maps ms)]
     (SomeJavaClass/someStaticVoidMethod merged, "some", "other", "stuff")
     merged))
于 2013-07-25T15:06:52.137 回答