'get'替换会在未找到的情况下抛出异常?

Mar*_*ars 1 clojure

我想访问地图和记录中的值,当密钥不存在时抛出异常.这是我尝试过的.有更好的策略吗?

这不起作用,因为throw每次评估:

(defn get-or-throw-1 [rec key]
  (get rec key (throw (Exception. "No value."))))
Run Code Online (Sandbox Code Playgroud)

也许有一个使用宏的简单方法?嗯,这不是它; 它与第一个定义具有相同的问题,即使评估throw发生在以后:

(defmacro get-or-throw-2 [rec key]
  `(get ~rec ~key (throw (Exception. "No value."))))
Run Code Online (Sandbox Code Playgroud)

这个通过让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)))
Run Code Online (Sandbox Code Playgroud)

我不想猜测哪些关键字或符号永远不会通过其他进程发生.(我可以用gensym产生的特殊价值not-found-thing,但我不明白为什么这会更好.我没有利用未发现-价值担心有人蓄意试图打败功能的目的地图或记录中的东西.)

有什么建议?

noi*_*ith 7

这是先决条件的意思.它们内置于语言中,应该用于输入验证(尽管如果前提条件对于特定情况不灵活,您也可以使用断言).

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)
Run Code Online (Sandbox Code Playgroud)


ama*_*loy 7

这是什么样find的功能是:(find m k)回报nil,如果没有被发现,或者[k v]如果从一个映射kv被发现.您可以随时区分这两者,而无需猜测地图中可能存在的内容.所以你可以写:

(defn strict-get [m k]
  (if-let [[k v] (find m k)]
    v
    (throw (Exception. "Just leave me alone!"))))
Run Code Online (Sandbox Code Playgroud)


man*_*nge 5

您可以使用命名空间限定的关键字,这可以减少意外使用关键字的机会:

(defn get-or-throw [coll key]
  (let [result (get coll key ::not-found)]
    (if (= result ::not-found)
      (throw (Exception. "No value."))
      result)))
Run Code Online (Sandbox Code Playgroud)

或者,您可以只使用contains?

(defn get-or-throw [coll key]
  (if (contains? coll key)
    (get coll key)
    (throw (Exception. "No value."))))
Run Code Online (Sandbox Code Playgroud)

这应该是安全的,因为您的地图/记录应该是不可变的。