在Java中,我通常会这样做,
MyObject o1 = new MyObject();
o1.doSomething();
MyObject o2 = new MyObject();
o2.doWith(o1);
MyObject o3 = new MyObject();
o3.doWithBoth(o1, o2);
在Clojure中,如果我使用let绑定,它可能看起来像,
(let [o1 (create-obj)]
(.doSomething o1)
(let [o2 (create-obj)]
(.doWith o2 o1)
(let [o3 (create-obj)]
(.doWithBoth o3 o1 o2))))
代码增长到右侧,这是丑陋且难以维护的。有更好的方法吗?
答案 0 :(得分:12)
(let [o1 (doto (create-obj) (.doSomething))
o2 (doto (create-obj) (.doWith o1))
o3 (doto (create-obj) (.doWithBoth o1 o2))]
...)
有关详细信息,请参阅(doc doto)
。
(更新:)这是有效的,因为在每种情况下,它都是您正在调用方法的新创建的对象。如果你想调用一个函数/方法,而新创建的对象在第一个参数位置以外的参数位置传入,你可能最好用noisesmith描述的_
技巧服务,尽管你可以使用doto
as->
void
。后者的优点是不会引入一个未被清除的未使用的本地(上次我检查过Clojure只清除后续代码中实际引用的本地文件),但如果你正在调用{{1 - 返回副作用的方法。
答案 1 :(得分:3)
标准习语是使用_
作为评估副作用的行的let绑定。
(let [o1 (create-obj)
_ (.doSomething o1)
o2 (create-obj)
_ (.doWith o2 o1)
o3 (create-obj)]
(.doWithBoth o3 o1 o2))
答案 2 :(得分:3)
以下(我的)解决方案是可行的,但味道不佳。毫无疑问,.dosomething
& c方法会调用它们应用的对象。所以我们正在做的是构建一个对象,将它绑定到一个本地名称,然后在幕后改变它。 Eugh!
Michal Marczyck的答案更可取,因为doto
返回变异的对象,然后绑定到本地名称,之后从未发生过变异。
我们不能指望Java互操作符合Clojure习语,但我们应该尝试标记违规行为,正如doto
所做的那样。
let
绑定从左到右。所以你可以用其中一个做到这一点:
(let [o1 (create-obj)
_ (.doSomething o1)
o2 (create-obj)
_ (.doWith o2 o1)
o3 (create-obj)]
(.doWithBoth o3 o1 o2))
这里我们绑定_
两次。这是被忽略的绑定的传统名称。据推测,.doSomething
,.doWith
和.doWithBoth
是针对副作用执行的。