【问题标题】:Clojure: multiple let bindingsClojure:多个 let 绑定
【发布时间】:2014-03-21 19:59:18
【问题描述】:

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

代码增长到右手边,丑陋且难以维护。有没有更好的方法来做到这一点?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    以下(我的)解决方案是可行的,但味道很差。 .dosomething &c 方法调用无疑会改变它们所应用的对象。所以我们正在做的是构造一个对象,将它绑定到一个本地名称,然后在幕后对其进行变异。哎呀!

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

    【讨论】:

      【解决方案2】:
      (let [o1 (doto (create-obj) (.doSomething))
            o2 (doto (create-obj) (.doWith o1))
            o3 (doto (create-obj) (.doWithBoth o1 o2))]
        ...)
      

      详情请见(doc doto)

      (更新:) 这很有效,因为在每种情况下,它都是您正在调用方法的新创建的对象。相反,如果您想调用一个函数/方法,并将新创建的对象传入第一个以外的参数位置,则最好使用由 noisesmith 描述的_ 技巧,尽管您可以使用@987654325 @ 和as->。后者的优点是不引入不会被清除的未使用本地(上次我检查 Clojure 只清除了后续代码中实际引用的本地),但如果你调用 void -返回副作用的方法。

      【讨论】:

      • 它将(as-> expr sym form1 form2 ...) 转换为(let [sym expr sym form1 sym form2 ...] sym)。请参阅 REPL (>= 1.5.0) 上的 (doc as->) 或关注 this link 在 Clojure API 页面上查看相同内容。 (我找不到指向 1.5.x API 的稳定链接,所以我改为链接到“当前”。)
      • 为了清楚起见,您可以在 doto 中使用 as->(doto 1 (as-> foo (+ foo 2) (* foo 3) (println foo))) 打印 9 并返回 1。
      • 我可以建议(new MyObject)代替(create-obj)吗? “惯用的 Clojure 代码直接调用 Java 库”Halloway。
      【解决方案3】:

      标准习惯用法是使用 _ 作为评估副作用的行的 let 绑定。​​

      (let [o1 (create-obj)
            _ (.doSomething o1)
            o2 (create-obj)
            _ (.doWith o2 o1)
            o3 (create-obj)]
        (.doWithBoth o3 o1 o2))
      

      【讨论】:

        猜你喜欢
        • 2012-04-11
        • 2014-06-19
        • 2013-05-31
        • 2015-11-20
        • 2014-01-23
        • 2018-08-27
        • 2010-11-04
        • 2015-06-04
        • 2015-03-24
        相关资源
        最近更新 更多