clojure 所有键的相同“:或”值

clojure same ":or" value for all keys

我定义了一个包含一堆字段的记录——其中一些是计算出来的,其中一些不直接映射到我正在摄取的 JSON 数据中的键。我正在为它写一个工厂函数,但我想要合理的 default/not-found 值。有没有更好的方法来解决 :or [field1 "" field2 "" field3 "" field4 ""...]?我可以写一个宏,但如果不需要的话我宁愿不写。

如果你真的希望所有字段的默认值相同,并且它们确实必须与nil不同,并且你不想再次写下它们,那么你可以获取记录通过在空实例上调用 keys 来构建字段,然后构造一个将默认值与实际值合并的映射:

(defrecord MyFancyRecord [a b c d])

(def my-fancy-record-fields (keys (map->MyFancyRecord {})))
;=> (:a :b :c :d)

(def default-fancy-fields (zipmap my-fancy-record-fields (repeat "")))

(defn make-fancy-record [fields]
  (map->MyFancyRecord (merge default-fancy-fields
                             fields)))

(make-fancy-record {})
;=> {:a "", :b "", :c "", :d ""}

(make-fancy-record {:a 1})
;=> {:a 1, :b "", :c "", :d ""}

要获取记录字段列表,您还可以在记录中使用静态方法 getBasis class:

(def my-fancy-record-fields (map keyword (MyFancyRecord/getBasis)))

(getBasis 不是 public 记录的一部分 api 所以不能保证它不会在未来的 clojure 版本中被删除。现在它在两个 clojure 中都可用和 clojurescript, it's usage is explained in "Clojure programming by Chas Emerick, Brian Carper, Christophe Grand" and it's also mentioned in this thread 在关于如何从记录中获取密钥的讨论中。因此,由您决定使用它是否是个好主意)

在构造函数中实现默认值有三种常见的习惯用法。

  1. :or 解构

    示例:

    (defn make-creature [{:keys [type name], :or {type :human
                                                  name (str "unnamed-" (name type))}}]
      ;; ...
      )
    

    当您想指定内联默认值时,这很有用。作为奖励,它允许 :or 映射中的 let 样式绑定,其中 kvs 根据 :keys 向量排序。

  2. 正在合并

    示例:

    (def default-creature-spec {:type :human})
    
    (defn make-creature [spec]
       (let [spec (merge default-creature-spec
                         spec)]
          ;; ....
          ))
    

    当你想在外部定义默认值时,这很有用,在运行时生成它们and/or在别处重用它们。

  3. 简单or

    示例:

    (defn make-creature [{:keys [type name]}]
      (let [type (or type :human)
            name (or name (str "unnamed-" (name type)))]
         ;; ...
         ))
    

    这与 :or 析构函数一样有用,但仅评估实际需要的那些默认值,即。 e.它应该用于计算默认值会增加不必要的开销的情况。 (我不知道为什么 :or 评估所有默认值(从 Clojure 1.7 开始),所以这是一个解决方法)。