我想访问地图和记录中的值,当密钥不存在时抛出异常。这是我尝试过的。有更好的策略吗?
这不起作用,因为每次评估throw
:
(defn get-or-throw-1 [rec key]
(get rec key (throw (Exception. "No value."))))
也许有一个使用宏的简单方法?嗯,这不是它;它与第一个定义具有相同的问题,即使throw
的评估稍后发生:
(defmacro get-or-throw-2 [rec key]
`(get ~rec ~key (throw (Exception. "No value."))))
这个通过让get
返回一个(理论上)永远不会以任何其他方式生成的值来工作:
(defn get-or-throw-3 [rec key]
(let [not-found-thing :i_WoUlD_nEvEr_NaMe_SoMe_ThInG_tHiS_021138465079313
value (get rec key not-found-thing)]
(if (= value not-found-thing)
(throw (Exception. "No value."))
value)))
我不想猜测通过其他进程永远不会出现哪些关键字或符号。 (我可以使用gensym
生成not-found-thing
的特殊值,但我不明白为什么会更好。我不必担心有人故意试图破坏目的通过在地图或记录中使用not-found-thing的值来起作用。)
有什么建议吗?
答案 0 :(得分:7)
这是preconditions的意思。它们内置于语言中,应该用于输入验证(尽管如果前提条件对于特定情况不灵活,您可以使用断言)。
user> (defn strict-get
[place key]
{:pre [(contains? place key)]}
(get place key))
#'user/strict-get
user> (strict-get {:a 0 :b 1} :a)
0
user> (strict-get {:a 0 :b 1} :c)
AssertionError Assert failed: (contains? place key) user/eval6998/fn--6999/strict-get--7000 (form-init7226451188544039940.clj:1)
答案 1 :(得分:6)
这是find
函数的用途:如果找不到任何内容,则(find m k)
会返回nil
,如果从[k v]
到{{k
,则会v
1}}被发现了。您可以随时区分这两者,并且不需要猜测地图中可能存在的内容。所以你可以写:
(defn strict-get [m k]
(if-let [[k v] (find m k)]
v
(throw (Exception. "Just leave me alone!"))))
答案 2 :(得分:3)
您可以使用名称空间限定关键字,这可以减少意外使用关键字的可能性:
(defn get-or-throw [coll key]
(let [result (get coll key ::not-found)]
(if (= result ::not-found)
(throw (Exception. "No value."))
result)))
或者,您可以使用contains?
:
(defn get-or-throw [coll key]
(if (contains? coll key)
(get coll key)
(throw (Exception. "No value."))))
这应该是安全的,因为你的地图/记录应该是不可变的。
答案 3 :(得分:1)
此功能也在名为grab
的{{3}}库中实施。请注意,参数顺序在此处是相反的,看似有意:(grab :my-key my-map)
。
答案 4 :(得分:0)
我更喜欢simulant的名称和实现:getx
和getx-in
(defn getx
"Like two-argument get, but throws an exception if the key is
not found."
[m k]
(let [e (get m k ::sentinel)]
(if-not (= e ::sentinel)
e
(throw (ex-info "Missing required key" {:map m :key k})))))
(defn getx-in
"Like two-argument get-in, but throws an exception if the key is
not found."
[m ks]
(reduce getx m ks))