如何在 Clojure 中捕获一个 arity 异常?
How to catch an arity exception in Clojure?
我正在尝试捕捉这样的异常:
(try
(inc)
(catch clojure.lang.ArityException e
(str "caught exception: " (.getMessage e))))))
在这种情况下,我在调用 inc
时没有给它传递一个数字,它正确地抛出了一个异常。但是,当我 运行 它时,该异常不会被捕获:
(try
(inc)
(catch clojure.lang.ArityException e
(str "caught exception: " (.getMessage e))))))
; => CompilerException clojure.lang.ArityException: Wrong number of args (0) passed to: core/inc--inliner--4489
通常尝试捕获任何 Exception
而不是 clojure.lang.ArityException
仍然会抛出它。
我相信在 Clojure 开发方面经验丰富的任何人都会立即发现我的错误。
在某些情况下您可以捕捉到 ArityException
;取决于导致 ArityException
.
的上下文和函数
我马上承认我在某些方面进行了推测,因为我以前从未深入探讨过这个问题。
首先,看看如果您在提供的参数数量明显错误的上下文中调用 inc
会发生什么:
(inc)
CompilerException clojure.lang.ArityException: Wrong number of args (0) passed to: core/inc--inliner--4489, compiling: . . .
有趣的部分是inc--inliner--4489
。如果您查看 inc
的定义,它会附加以下元数据:
:inline (fn [x] `(. clojure.lang.Numbers (~(if *unchecked-math* 'unchecked_inc 'inc) ~x)))
我以前从未深入研究过 :inline
,但我一直假设这意味着它将尝试内联调用以(略微)减少开销。在这种情况下,它试图将 inc
内联为对 clojure.lang.Numbers/inc
或 clojure.lang.Numbers/unchecked_inc
的调用;取决于 *unchecked-math*
的状态。还要注意错误是如何开始的:
CompilerException clojure.lang.ArityException
在您的示例中,您无法直接捕获 (inc)
,因为该调用在代码 运行 之前的 编译时间 失败。它知道 (inc)
永远不会正确,所以它立即失败。不过,这是一件好事。 (inc)
将永远不会正确,所以无论如何都没有必要试图抓住它。
然而,在某些情况下,捕获一个 arity 异常 可能 是有意义的(尽管可能有更好的方法来解决这个问题 *
)。假设您不允许对 inc
的调用被内联,正如@Rulle 建议的那样,apply
ing 参数:
(try
(apply inc [])
(catch clojure.lang.ArityException e
(println "Caught!")))
Caught!
编译器无法确定 inc
是否会失败,因为它取决于提供给 apply
的参数数量;这可能取决于 运行 时间的事情。在这种情况下,代码实际上能够 运行,并且也能够使其 ArityException
被捕获。
将 :inline
排除在等式之外,您还可以看到您的自定义函数可以更轻松地捕获其 ArityException
,因为调用不是内联的,所以它不会' 在编译时失败:
(defn hello [arg])
(try
(hello) ; No apply
(catch clojure.lang.ArityException e
(println "Caught!")))
Caught!
*
我不能说我曾经必须赶上 ArityException
,而且我想不出在任何情况下这样做是合适的。即使您正在使用 apply
,提前验证参数甚至重新考虑您对 apply
的使用也会更有意义。如果使用 apply
导致 ArityException
,您的逻辑中可能存在缺陷,使用 try
只是贴上创可贴。
我正在尝试捕捉这样的异常:
(try
(inc)
(catch clojure.lang.ArityException e
(str "caught exception: " (.getMessage e))))))
在这种情况下,我在调用 inc
时没有给它传递一个数字,它正确地抛出了一个异常。但是,当我 运行 它时,该异常不会被捕获:
(try
(inc)
(catch clojure.lang.ArityException e
(str "caught exception: " (.getMessage e))))))
; => CompilerException clojure.lang.ArityException: Wrong number of args (0) passed to: core/inc--inliner--4489
通常尝试捕获任何 Exception
而不是 clojure.lang.ArityException
仍然会抛出它。
我相信在 Clojure 开发方面经验丰富的任何人都会立即发现我的错误。
在某些情况下您可以捕捉到 ArityException
;取决于导致 ArityException
.
我马上承认我在某些方面进行了推测,因为我以前从未深入探讨过这个问题。
首先,看看如果您在提供的参数数量明显错误的上下文中调用 inc
会发生什么:
(inc)
CompilerException clojure.lang.ArityException: Wrong number of args (0) passed to: core/inc--inliner--4489, compiling: . . .
有趣的部分是inc--inliner--4489
。如果您查看 inc
的定义,它会附加以下元数据:
:inline (fn [x] `(. clojure.lang.Numbers (~(if *unchecked-math* 'unchecked_inc 'inc) ~x)))
我以前从未深入研究过 :inline
,但我一直假设这意味着它将尝试内联调用以(略微)减少开销。在这种情况下,它试图将 inc
内联为对 clojure.lang.Numbers/inc
或 clojure.lang.Numbers/unchecked_inc
的调用;取决于 *unchecked-math*
的状态。还要注意错误是如何开始的:
CompilerException clojure.lang.ArityException
在您的示例中,您无法直接捕获 (inc)
,因为该调用在代码 运行 之前的 编译时间 失败。它知道 (inc)
永远不会正确,所以它立即失败。不过,这是一件好事。 (inc)
将永远不会正确,所以无论如何都没有必要试图抓住它。
然而,在某些情况下,捕获一个 arity 异常 可能 是有意义的(尽管可能有更好的方法来解决这个问题 *
)。假设您不允许对 inc
的调用被内联,正如@Rulle 建议的那样,apply
ing 参数:
(try
(apply inc [])
(catch clojure.lang.ArityException e
(println "Caught!")))
Caught!
编译器无法确定 inc
是否会失败,因为它取决于提供给 apply
的参数数量;这可能取决于 运行 时间的事情。在这种情况下,代码实际上能够 运行,并且也能够使其 ArityException
被捕获。
将 :inline
排除在等式之外,您还可以看到您的自定义函数可以更轻松地捕获其 ArityException
,因为调用不是内联的,所以它不会' 在编译时失败:
(defn hello [arg])
(try
(hello) ; No apply
(catch clojure.lang.ArityException e
(println "Caught!")))
Caught!
*
我不能说我曾经必须赶上 ArityException
,而且我想不出在任何情况下这样做是合适的。即使您正在使用 apply
,提前验证参数甚至重新考虑您对 apply
的使用也会更有意义。如果使用 apply
导致 ArityException
,您的逻辑中可能存在缺陷,使用 try
只是贴上创可贴。