在 Clojure 中捕获多个异常并以相同的方式处理它们

Catch multiple exceptions in Clojure and handle them the same

这个和this question有点类似,但是我想捕获多个异常,并统一处理。在Ruby,我可以写

begin
  rand(2) == 0 ? ([] + '') : (foo)
rescue TypeError, NameError => e
  puts "oops: #{e.message}"
end

我可以在 Clojure 中做同样的事情吗?现在我 let 一个函数并在每个 catch 主体中调用它。

目前还没有简单的内置解决方案,但是,open ticket

您可以在 catch 块中手动编写 dispatch on type。

(try
  (do-dangerous-operation-here)
  (catch Exception e
    (condp (fn [cs t] (some #(instance? % t) cs)) e

      [IllegalStateException IllegalArgumentException]
      (println "Either illegal state or illegal argument!")

      [java.sql.SQLException]
      (println "Sql error!")

      ;; whe pass through the exception when not handled
      (throw e))))
(ns mastering.Whosebug
    (:use
        [slingshot.slingshot :only [try+]]))


(try+
    ; ...
    (catch (comp #{TypeError NameError} class) _ "caught"))

The slingshot library 在 github 可用。

您也可以委托给本地函数,尽管它有点冗长:

(let [handle #(println %)]
  (try
    (throwing-op)

    (catch TypeError e (handle e))
    (catch NameError e (handle e))))

你也可以使用这个宏:

(defmacro try*
  "Macro to catch multiple exceptions with one catch body.
   Usage:
   (try*
     (println :a)
     (println :b)
     (catch* [A B] e (println (class e)))
     (catch C e (println :C))
     (finally (println :finally-clause)))
   Will be expanded to:
   (try
     (println :a)
     (println :b)
     (catch A e (println (class e)))
     (catch B e (println (class e)))
     (catch C e (println :C))
     (finally (println :finally-clause)))
  "
  [& body]
  (letfn [(catch*? [form]
            (and (seq form)
                 (= (first form) 'catch*)))
          (expand [[_catch* classes & catch-tail]]
            (map #(list* 'catch % catch-tail) classes))
          (transform [form]
            (if (catch*? form)
              (expand form)
              [form]))]
    (cons 'try (mapcat transform body))))

学分 https://gist.github.com/Gonzih/5814945