为什么这个例外没有被抓住?

时间:2017-12-09 20:16:27

标签: clojure

如果我定义以下功能

(defn catcher [x] (try 
    (load-string x)
    (catch Exception e 
        (prn "caught"))) )

(catcher "(+ 2 \"2\")") => "抓"

但是(catcher "(keys [1 2])") => ClassCastException java.lang.Long无法强制转换为java.util.Map $ Entry

通常这两个输入都抛出ClassCastException,那么为什么只有第一个被捕获?

2 个答案:

答案 0 :(得分:1)

在尝试打印 (keys [1 2])的结果时,似乎发生了异常。

(type (catcher "(keys [1 2])"))
=> clojure.lang.APersistentMap$KeySeq

在这里你可以看到表达式实际上是创建/返回KeySeq而不抛出/捕获异常。只有当KeySeq 打印时才会抛出异常:

java.lang.ClassCastException: java.lang.Long cannot be cast to java.util.Map$Entry
    at clojure.lang.APersistentMap$KeySeq.first(APersistentMap.java:168)
    at clojure.lang.RT.first(RT.java:685)
    at clojure.core$first__5107.invokeStatic(core.clj:55)
    at clojure.core$print_sequential.invokeStatic(core_print.clj:64)
    at clojure.core$fn__7021.invokeStatic(core_print.clj:174)
    at clojure.core$fn__7021.invoke(core_print.clj:174)
    at clojure.lang.MultiFn.invoke(MultiFn.java:233)
    at clojure.tools.nrepl.middleware.pr_values$pr_values$fn$reify__784.send(pr_values.clj:35)

请注意,在堆栈跟踪中,此异常源自KeySeq.first方法(在 实现打印顺序。

答案 1 :(得分:0)

请注意[1 2],当您输入时,{* 1}}是一个clojure vector字面值,而不是Clojure MapEntry。看到这些结果:

(ns tst.demo.core
  (:use tupelo.test)
  (:require
    [tupelo.core :as t] ) )
(t/refer-tupelo)

(dotest
  (newline)
  (let [my-map      {:a 1 :b 2}
        map-entries (vec my-map)
        map-entry-1 (first map-entries)
        map-keys    (keys my-map)
        entry-1-key (key map-entry-1)
  ]
    (is= map-entries [[:a 1] [:b 2]] )
    (is= map-entry-1 [:a 1] )
    (is= map-keys [:a :b])
    (is= entry-1-key :a)

    (spyxx my-map)
    (spyxx map-entries)
    (spyxx map-entry-1)
    (spyxx map-keys)
    (spyxx entry-1-key)
  ))

结果:

Testing tst.demo.core

my-map        => <#clojure.lang.PersistentArrayMap {:a 1, :b 2}>
map-entries   => <#clojure.lang.PersistentVector [[:a 1] [:b 2]]>
map-entry-1   => <#clojure.lang.MapEntry [:a 1]>
map-keys      => <#clojure.lang.APersistentMap$KeySeq (:a :b)>
entry-1-key   => <#clojure.lang.Keyword :a>

Ran 2 tests containing 4 assertions.
0 failures, 0 errors.

问题是MapEntry打印与矢量相同:

`[1 2]`

但是,它们是不同的类型。执行(load-string "[1 2]")时,它会返回向量,而不是地图,因此您无法调用keys函数。

第2部分

在您的原始问题中,您询问

(catcher "(keys [1 2])") => Exception

我怀疑load-string正在返回一个惰性结果,直到你的代码退出try-catch块之后才能实现,这就是没有捕获异常的原因。