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

欢迎!请参阅关于页面以获取更多有关如何使用本站的信息。

0
错误

09:43 $ clj
Clojure 1.8.0
(defmulti foo :bar)
(defmethod foo :qix [quux znoot] (println 'hi))
#'user/foo
user=> #object[clojure.lang.MultiFn 0x205d38da "clojure.lang.MultiFn@205d38da"]
user=> (foo {:bar :qix})
ArityException 错误参数个数 (1),传入至:user/eval5/fn--6  clojure.lang.AFn.throwArity (AFn.java:429)
user=>


这是一个实现细节,多方法通过匿名函数实现。我预期错误信息至少包含失败函数的名称,在这种情况下,它应该是这样的:


ArityException 错误参数个数 (1),传入至:user/eval5/foo--6  clojure.lang.AFn.throwArity (AFn.java:429)


这里可以采用几种方法

第一种(也是 simplest)是更改`{{defmethod}}`的定义,使匿名函数有名称。
这会导致错误信息如:

user=> (defmulti foo :bar)
(defmethod foo :qix [quux znoot] (println 'hi))
(foo {:bar :qix})#'user/foo
user=> #object[clojure.lang.MultiFn 0x4e928fbf "clojure.lang.MultiFn@4e928fbf"]
user=>
ArityException 错误参数个数 (1),传入至:user/eval5/foo--6  clojure.lang.AFn.throwArity (AFn.java:429)
user=>

此外,可以修改Compiler.java以查找对"addMethod"的调用

String prefix = "eval";
if (RT.count(form) > 2) {
   Object third = RT.nth(form, 2);
   if (third != null &&
       "clojure.core/addMethod".equals(third.toString()))
      prefix = "multi_fn";
}
ObjExpr fexpr = (ObjExpr) analyze(C.EXPRESSION, RT.list(FN, PersistentVector.EMPTY, form), prefix + RT.nextID());

这将使我们获得错误信息如:

ArityException 错误参数个数 (1),传入至:user/multi-fn5/foo--6  clojure.lang.AFn.throwArity (AFn.java:441)

2 答案

0

评论者:alexmiller

有趣的是,实际上可以为defmethods指定名称,该名称会包含在其类名中。defmethod的参数列表为:((link: multifn dispatch-val & fn-tail)),其中fn-tail是传递给fn的尾部参数,包括一个可选的名称。

因此,您可以这样做

`
(defmulti foo class)
;; 创建名为 HI 的 defmethod
(defmethod foo String HI [x] (throw (Exception. (str "hi " x)))))

;; 调用
(foo "bleh")
Exception hi bleh user/eval1248/HI--1249 (form-init1348837216879020682.clj:1)
`

注意类名中的 HI。这并不涵盖所有情况,但它是一个有用的调试技巧。

0
参考资料: https://clojure.atlassian.net/browse/CLJ-2263(由slipset报告)
...