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)`s”列表。根据https://clojure.org/reference/evaluation, 除了特殊形式之外,每个形式都是表达式。`(catch Exception e)`是一个特殊形式,因此不一定是表达式。因此,它不一定是`binding`的有效输入。看来`binding`可以修改以处理这种输入而不破坏文档字符串,但当前的文档字符串与当前的行为相匹配,这正是我真正担心的地方。
...