请分享您的想法,参加 2024 年 Clojure 状态调查!

欢迎!请查看关于页面获取更多关于这个平台的信息。

0

关于 clojure.core/binding 的文档字符串表示它 "以隐式 do 执行 exprs"。因此,预期的体元素将按顺序执行,返回最后一个的值(参照 do 的文档字符串)。

然而,体表达式并没有被包裹在 dolet 中,而是被 try 包裹。这导致了一些令人惊讶的行为

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

上述表达式返回 :failure,而下面的表达式更明显地引发了编译器异常,因为没有 trycatch 无法使用。

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

从 git 历史来看,这个实现细节自 2008 年以来没有变化,所以可能有一些很好的理由。如果是这样,原因是什么?如果不是,我们能将 binding 的实现更改,使其在 ~@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`期望body是一个“表达式”列表。根据https://clojure.org/reference/evaluation,除了特殊形式外,每个形式都是一个表达式。“`(catch Exception e)`”是一个特殊形式,因此它不一定是表达式。因此,它不一定是`binding`的合法输入。看起来`binding`可以修改以处理这种输入而不使文档字符串无效,但当前的文档字符串与当前的行为相匹配,这正是我真正担忧的。
...