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

欢迎!请参阅关于页面以了解更多关于其工作方式的信息。

0
\"\" 提问 Laverne Schrock

文档字符串说明 clojure.core/binding 在"隐式执行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
\"\" 回答 alexmiller
 
最佳答案

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