请分享您的想法在2024年的Clojure状态调查中!

欢迎!请查看关于页面以了解更多关于如何使用本网站的信息。

0

clojure.core/binding的文档字符串表示它“在隐式do中执行exprs”。因此,我预计主体元件将按顺序执行,并返回最后一个的值(参见do的文档字符串)。

但是,主体表达式不是被封装在do或者let中,而是被封装在try中。这导致了一些令人惊讶的行为

(binding [clojure.core/*print-length* 10]
  (/ 10 0)
  (catch Exception e
    :failure))

上面的表达式返回`:failure`,而下面的表达式显然会抛出编译器异常,因为没有try,就不能使用catch

(binding [clojure.core/*print-length* 10]
  (do 
    (/ 10 0)
    (catch Exception e
      :failure)))

据我对git历史的观察,这一实现细节自2008年以来没有改变,所以可能有一些很好的理由。如果有,那是什么呢?如果没有,我们能改变宏绑定实现的实现,使其在~@body周围实际上有一个do吗?

1 答案

+2

 
最佳答案

try中有一个隐式do - 你想要做什么却不起作用呢?

(binding []
  (println "1")
  (println "2")
  3)
;; 1
;; 2
;;=> 3
"你想要做什么,却出不来结果?" 这是一个合理的问题,答案是“没有”。相反,有一个(我在原始问题中的第一个代码块)可以正常工作,但我预计它会失败。
好吧,不要这样做。
(当我这么说“工作”的时候,我的意思是它返回了一个值而不是抛出一个异常)
大概是它必须使用 try/finally,这样无论被包装的代码成功或失败都能弹出绑定组件?
@Sean Corfield
没错,但是它可以在主体周围增加一个额外的 `do`,以防止调用者在 `try` 的末尾添加额外的 `catch` 子句。

@Alex Miller
显然,我绝不会故意这样做。:)

因此,我做了更多的阅读,并意识到你是正确的。`binding`期望主体是一个“expr(ession)s”的列表。根据https://clojure.org/reference/evaluation, 每个形式都是一个表达式,除了特殊形式。`(catch Exception e)`是一个特殊形式,因此不一定是表达式。因此,它不一定是`binding`的有效输入。看起来`binding`可以修改以处理这种输入而不使文档字符串无效,但当前的文档字符串与当前的行为一致,这正是我真正担心的。
...