如何在Clojure中为记录中的字段设置默认值?

如何在Clojure中为记录中的字段设置默认值?,clojure,Clojure,我正在Clojure中创建记录,希望使用默认值设置一些字段。如何执行此操作?通过扩展映射构造记录时,可以非常轻松地将初始值传递给记录: (defrecord Foo []) (def foo (Foo. nil {:bar 1 :baz 2})) 有鉴于此,我通常创建一个构造函数,该构造函数合并一些默认值(您可以根据需要覆盖这些值): 使用构造函数 (defrecord Foo [a b c]) (defn make-foo [& {:keys [a b c] :or {a 5

我正在Clojure中创建记录,希望使用默认值设置一些字段。如何执行此操作?

通过扩展映射构造记录时,可以非常轻松地将初始值传递给记录:

(defrecord Foo [])

(def foo (Foo. nil {:bar 1 :baz 2}))
有鉴于此,我通常创建一个构造函数,该构造函数合并一些默认值(您可以根据需要覆盖这些值):


使用构造函数

(defrecord Foo [a b c])

(defn make-foo
  [& {:keys [a b c] :or {a 5 c 7}}]
  (Foo. a b c))

(make-foo :b 6)
(make-foo :b 6 :a 8)
当然有各种各样的变化。例如,您可以要求某些字段是非可选的,并且没有默认值

(defn make-foo
  [b & {:keys [a c] :or {a 5 c 7}}]
  (Foo. a b c))

(make-foo 6)
(make-foo 6 :a 8)

YMMV。

在提出同样的问题后,我最终使用宏将defrecord和factory函数包装到一个定义中

宏:

(defmacro make-model
  [name args & body]
  (let [defaults (if (map? (first body)) (first body) {})
        constructor-name (str/lower-case (str "make-" name))]
    `(do (defrecord ~name ~args ~@(if (map? (first body)) (rest body) body))
         (defn ~(symbol constructor-name)
           ([] (~(symbol constructor-name) {}))
           ([values#] (~(symbol (str "map->" name)) (merge ~defaults values#)))))))
用法


这个链接解释了:键和:的用法,或者你也可以像这样使用
map->Foo
和/或
->Foo
(defn make Foo[&args](map->Foo(变成args{:a5:b1:c7}))(make Foo{:b3})-它节省了一点解构
(defmacro make-model
  [name args & body]
  (let [defaults (if (map? (first body)) (first body) {})
        constructor-name (str/lower-case (str "make-" name))]
    `(do (defrecord ~name ~args ~@(if (map? (first body)) (rest body) body))
         (defn ~(symbol constructor-name)
           ([] (~(symbol constructor-name) {}))
           ([values#] (~(symbol (str "map->" name)) (merge ~defaults values#)))))))
(make-model User [firstName lastName] {:lastName "Smith"})
=> #'user/make-user
(make-user {:firstName "John"})
=> #user.User{:firstName "John", :lastName "Smith"}