Clojure:多个let绑定

时间:2014-02-20 17:27:42

标签: clojure

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

代码增长到右侧,这是丑陋且难以维护的。有更好的方法吗?

3 个答案:

答案 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是针对副作用执行的。