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

欢迎!有关此平台的更多信息,请参阅 关于 页面。

0
错误
已关闭

问题描述

clojure.core/deref 函数在接收一个非clojure.lang.IDerefjava.util.concurrent.Future类型的对象时,会抛出一个难以解码的ClassCastException异常。在我的经验中,向新Clojure用户介绍(在我的工作和我的开源项目中),这种情况时常发生,并且可能会造成很大困惑,因为它没有指向代码中的任何明显位置。即使有堆栈跟踪,它也只指向deref-future的定义(而不是函数体内的特定行),这进一步加剧了困惑。

讨论

在Slack上,我建议修改deref的实现,使其类似于以下代码:(cond(instance? clojure.lang.IDeref ref)...(instance? java.util.concurrent.Future ref)...:else(throw(IllegalArgumentException(str ref “无法 deref 为它当前类型为” (class ref).”))))。

Sean Corfield提到了这样的修复会降低所有非-IDeref类型使用deref时的性能,我已经接受这一点,尽管我感到不满意。

重现

user=> (def a {})
#'user/a

user=> @a
Execution error (ClassCastException) at user/eval22861 (REPL:0).
class clojure.lang.PersistentArrayMap cannot be cast to class java.util.concurrent.Future (clojure.lang.PersistentArrayMap is in unnamed module of loader 'app'; java.util.concurrent.Future is in module java.base of loader 'bootstrap')

user=> (pst)
ClassCastException class clojure.lang.PersistentArrayMap cannot be cast to class java.util.concurrent.Future (clojure.lang.PersistentArrayMap is in unnamed module of loader 'app'; java.util.concurrent.Future is in module java.base of loader 'bootstrap')
    clojure.core/deref-future (core.clj:2315)
    clojure.core/deref-future (core.clj:2315)
    clojure.core/deref (core.clj:2338)
    clojure.core/deref (core.clj:2323)
    user/eval22863 (NO_SOURCE_FILE:0)
    user/eval22863 (NO_SOURCE_FILE:-1)
    clojure.lang.Compiler.eval (Compiler.java:7194)
    clojure.lang.Compiler.eval (Compiler.java:7149)
    clojure.core/eval (core.clj:3215)
    clojure.core/eval (core.clj:3211)
    clojure.main/repl/read-eval-print--9206/fn--9209 (main.clj:437)
    clojure.main/repl/read-eval-print--9206 (main.clj:437)
看起来这与https://ask.clojure.org/index.php/1553/error-message-when-calling-deref-on-non-ideref-is-unhelpful是重复的,不幸的是,我发布后才找到它。
谢谢,我在ask和jira上也都找不到,将对此进行重复。
...