检查地图中所有 clojure 值的有效性

Checking validity of all clojure values in a map

是否有一种简洁、惯用的方法来检查映射的所有值是否不为空或 0。

如果我有下面的地图

{"id" 10 "Department" "UI Design" "managerid" 4}

迭代映射值并确保字符串不为空 ("") 或 nil 且 ints/longs 不为 0 或 nil 的最简洁方法是什么。

本质上,我试图在将某些输入提交给数据库之前对其进行验证。我知道我可以使用像 Prismatic/schema 这样的库,但现在我想知道没有这个如何实现它。

此映射仅包含字符串和 ints/longs,但它可以包含其他类型。

有通用的方法吗?

Multimethods 可以为给定问题提供优雅的解决方案:

; for now dispatch is based only on value type
(defmulti valid? (fn [[k v]] (class v)))

(defmethod valid? java.lang.Long [[_ value]] (not (zero? value)))
(defmethod valid? java.lang.String [[_ value]] (not (empty? value)))
(defmethod valid? nil [_] false)
(defmethod valid? :default [_] true) ; valid for rest cases

查看整个地图:

(every? valid? your-map)

示例:

(every? valid? {:a 1 :b 0}) ; false
(every? valid? {:a 1 :b 1}) ; true
(every? valid? {:a 1 :b ""}) ; false
(every? valid? {:a 1 :b "a"}) ; true
(every? valid? {:a 1 :b "a" :c []}) ; true

几点注意事项:

  • (not (empty? value)) 可以替换为 (not-empty value)(seq value),但在这两种情况下,将返回字符串的完整值而不是布尔值(仍将计算为 true当然)。
  • 您不能检查 nil 的数字或字符串,因为 nil 有自己的类型。在上面的示例中,所有 nil 值都被视为无效。如果对于某些键 nils 是可以接受的 - 调度函数 (fn [[k v]] (class v)) 应该更改为也考虑到键。

这个解决方案比像

这样的简单函数要长一些
(defn valid? [[k v]]
  (cond (string? v) (not (empty? v))
  ...
  :else true))

但它更易于维护和扩展。

编辑。如评论中所述,惯用的方法是使用 (seq coll) 而不是 (not (empty? coll)),因为 empty? 的定义类似于 (not (seq coll))。您可能仍想保留 (not (empty? coll)) 检查以使验证代码更加明确和明显。