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

时间:2015-01-21 20:05:55

标签: clojure

是否有一种干净,惯用的方法来检查地图的所有值是否为空或0。

例如,如果我有以下地图

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

什么是迭代地图值的最简洁方法,并确保字符串不为空("")或nil,而int / long不是0或nil。

基本上我在尝试将一些输入提交给DB之前尝试验证。我知道我可以使用像Prismatic / schema这样的库,但是现在我想知道如果没有它可以实现它。

此地图仅包含字符串和整数/长整数,但它可能包含其他类型。

有没有通用的方法呢?

1 个答案:

答案 0 :(得分:5)

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))检查,以使验证代码更明确,更明显。