如果出现错误的类型,防止运行时错误

时间:2020-01-13 09:24:37

标签: if-statement error-handling clojure

我目前正在尝试建立一个简单的函数,该函数读取一个整数列表并按如下所示返回每个整数的平方:

(defn square-seq
  [s]
  (if (string? s)
    (s = nil)
    (map #(* % %) s)))

但是,我希望代码能够处理字符串输入,并将它们默认设置为数值以防止ClassCastException。就像我这样做

(square-seq ["Hello" 2 3])

然后返回值为:

(1 4 9) or (nil)

不知道我是想得太多还是只是太笨了,但我不知道如何让它在我的一生中发挥作用,任何帮助将不胜感激!

4 个答案:

答案 0 :(得分:0)

您正在检查顶级字符串,因此您极有可能永远不会到达该分支。您必须检查它实际触发错误的位置(在anon-fn内部)。

所以我先写一个函数,做一个“安全平方”,您的async function transformUser(userId, loaders) { const user = await loaders.userLoader.load(userId.toString()); return { ...user._doc, createdOrchestras: await Promise.all( user._doc.createdOrchestras.map(orchestra => transformOrchestra(orchestra, loaders) ) ) } } async function transformOrchestra(orchestraId, loaders) { const orchestra = await loaders.orchestraLoader.load(orchestraId.toString()); return { ...orchestra._doc, owner: transformUser(orchestra._doc.owner, loaders) } } module.exports = { transformUser, transformOrchestra } 可以调用它。

square-seq

答案 1 :(得分:0)

作为练习,我会提出如下实用函数:

(letfn [(single-or-all [arg & args] (if (seq args)
                                      (vec (cons arg args))
                                      arg))]
  (defn mapper [f & {:keys [guard guard-failed]
                     :or {guard (constantly true)
                          guard-failed single-or-all}}]
    (fn [& items] (if (apply guard items)
                    (apply f items)
                    (apply guard-failed items)))))

这里的mapper工厂函数会生成保护输入的函数,并在保护失败的情况下导致回退函数调用:

;; default usage:
user> (map (mapper #(* % %)) [1 2 3])
;;=> (1 4 9)

;; guard with default result:
user> (map (mapper #(* % %) :guard number?) [1 2 "aaa" 3])
;;=> (1 4 "aaa" 9)

;; guard with custom result:
user> (map (mapper #(* % %)
                   :guard number?
                   :guard-failed (constantly -1)) [1 2 "aaa" 3])
;;=> (1 4 -1 9)

;; multiple collections mapping with guards:
user> (map (mapper +
                  :guard #(every? number? %&))
           [1 2 "aaa" 3]
           [10 "zzz" 20 30])
;;=> (11 [2 "zzz"] ["aaa" 20] 33)

user> (map (mapper +
                   :guard #(every? number? %&)
                   :guard-failed (partial vector :guard/failed))
           [1 2 "aaa" 3]
           [10 "zzz" 20 30])
;;=> (11 [:guard/failed 2 "zzz"] [:guard/failed "aaa" 20] 33)

user> (map (mapper +
                   :guard #(every? number? %&)
                   :guard-failed #(apply + (filter number? %&)))
           [1 2 "aaa" 3]
           [10 "zzz" 20 30]
           [100 "x" 200 300])
;;=> (111 2 220 333)

答案 2 :(得分:0)

好像是一个简单的try/catch的场合:

(defn square
  [x]
  (try
    (* x x)
    (catch Exception ex
      :error)))

和用法:

(mapv square ["hello" 2 3]) => [:error 4 9]

尽管我会争辩说呼叫者应该有try/catch语句,因为当存在非数字时,只有呼叫者能够(也许!)做一些聪明的事情。

答案 3 :(得分:0)

我将尝试回答“防止运行时错误” 部分。基本思想是用异常处理程序包装目标函数,以便可以(使用另一个函数)处理运行时错误。使用通用处理程序,您可以轻松地将此机制应用于您使用的任何目标函数...

(defn square-seq
  [xs]
  ;; here safe-fn is a high order function to make * safe
  ;; by attaching an exception handler to it (which always return 1)
  (map (safe-fn * (constantly 1)) xs xs))

(square-seq ["Hello" 2 3])
;; => (1 4 9)

(defn half-seq
  [xs]
  ;; here we make / safe and also provide a different handler
  (map (safe-fn / (constantly 99)) xs (repeat 2)))

(half-seq ["Hello" 2 3])
;; => (99 1 3/2)

(defn triple-seq
  [xs]
  ;; yet another handler
  (apply map (safe-fn * (constantly 3)) (repeat 3 xs)))

(triple-seq ["Hello" 2 3])
;; => (3 8 27)

safe-fn可以很容易地实现为:

(defn safe-fn [f ex-handler]
  (fn [& args]
    (try
      (apply f args)
      (catch Throwable t
        (ex-handler t args)))))