【问题标题】:Checking validity of all clojure values in a map检查地图中所有 clojure 值的有效性
【发布时间】:2015-01-21 20:05:54
【问题描述】:

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

例如,如果我有以下地图

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

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

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

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

有通用的方法吗?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    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 值都被视为无效。如果某些键的 nil 是可以接受的 - 调度函数 (fn [[k v]] (class v)) 应更改为也将键考虑在内。

    这个解决方案比像这样的简单函数要长一些

    (defn valid? [[k v]]
      (cond (string? v) (not (empty? v))
      ...
      :else true))
    

    但它更易于维护和扩展。

    编辑。如 cmets 中所述,惯用方式是使用(seq coll) 而不是(not (empty? coll)),因为empty? 的定义类似于(not (seq coll))。您可能仍希望保持(not (empty? coll)) 选中以使验证代码更加明确和明显。

    【讨论】:

    • Clojure docs for empty? 说:“请使用成语 (seq x) 而不是 (not (empty?x))”,因为 (empty? coll) 被定义为 (not (seq coll))--so @987654343 @ 将运行 (not (not (seq x)))。无论如何,有些人更喜欢(not (empty? x)),但官方的说法是(seq x)是惯用的方式。
    • @Mars 谢谢。我已将此添加到答案中。
    猜你喜欢
    • 2020-06-18
    • 2020-01-08
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 1970-01-01
    • 2011-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多