2024 Clojure 州调查!中分享您的想法。

欢迎!请查阅关于页面以了解此工作的更多信息。

0 投票

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

然而,体表达式不是被包裹在 dolet 中,而是包裹在一个 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 年以来 hasn't changed,因此可能有一些合理的理由。如果有的话,那是什么?如果没有,我们能否将 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`期望体是一个"表达式(list of "expr(ession)s")"列表。根据https://clojure.org/reference/evaluation,每个形式都是表达式,除了特殊形式。`(catch Exception e)`是一个特殊形式,因此它不一定是表达式。因此,它不一定是`binding`的有效输入。看来`binding`可以被修改来处理这种输入而不使文档字符串无效,但当前的文档字符串与当前的行为相匹配,这正是我真正担忧的事情。
...