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

欢迎!请查看关于 页面了解有关如何使用此页面的更多信息。

0

clojure.core/binding 的文档字符串表示它 "在隐含的 do 中执行 exprs"。因此,我预期体中的元素将按顺序执行,并返回最后一个表达式的值(参见表达式 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 年以来这个实现细节没有改变,所以可能有些很好的理由。如果是这样,那是什么?如果不是,我们能否将 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` 预期主体是一个“expr(ession)”列表。根据https://clojure.org/reference/evaluation, 除了特殊形式外,每个形式都是一个表达式。`(catch Exception e)` 是一个特殊形式,因此它不一定是一个表达式。因此,它不一定可以作为 `binding` 的有效输入。看来 `binding` 可能可以修改来处理这种输入,而不违反文档字符串,但当前的文档字符串与当前的行为相符,这正是我真正担心的问题。
...