不需要函数,也不要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”可能会有点误导,但希望我能说服您节省几行冗余代码。