我已经使用一堆字段定义了一个记录 - 其中一些是计算的,其中一些不直接映射到我正在摄取的JSON数据中的键。我正在为它编写一个工厂函数,但我希望有合理的默认值/未找到值。是否有更好的方法来解决:or [field1 "" field2 "" field3 "" field4 ""...]
?我可以写一个宏但是如果我没有,我宁愿不去。
答案 0 :(得分:1)
在构造函数中实现默认值有三种常用的习惯用法。
:or
析构
示例:
(defn make-creature [{:keys [type name], :or {type :human
name (str "unnamed-" (name type))}}]
;; ...
)
当您想要指定内联默认值时,这非常有用。作为奖励,它允许在let
地图中:or
样式绑定,其中根据:keys
向量对kv进行排序。
合并
示例:
(def default-creature-spec {:type :human})
(defn make-creature [spec]
(let [spec (merge default-creature-spec
spec)]
;; ....
))
当您想要在外部定义默认值,在运行时生成默认值和/或在其他地方重复使用默认值时,这非常有用。
简单or
示例:
(defn make-creature [{:keys [type name]}]
(let [type (or type :human)
name (or name (str "unnamed-" (name type)))]
;; ...
))
这与:or
析构函数一样有用,但只评估那些实际需要的默认值,即:即它应该用于计算默认值会增加不必要的开销的情况。 (我不知道为什么:or
评估所有默认值(截至Clojure 1.7),所以这是一种解决方法。
答案 1 :(得分:0)
如果你真的想要所有字段的默认值相同,并且它们必须与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
:
(def my-fancy-record-fields (map keyword (MyFancyRecord/getBasis)))
(getBasis
不是公共记录api的一部分,因此无法保证在将来的clojure版本中它不会被删除。现在它可用于clojure和{{3它的用法在Chas Emerick,Brian Carper,Christophe Grand等人的Clojure编程中得到了解释,并且在讨论如何获得时也提到了clojurescript来自记录的密钥。因此,由您决定是否使用它是个好主意。