Я создаю записи в Clojure и хотел бы установить некоторые поля со значением по умолчанию. Как я могу это сделать?
Как установить значения по умолчанию для полей в записях в Clojure?
Ответ 1
Вы можете легко передать начальные значения в запись, когда вы его создаете, хотя карта расширения:
(defrecord Foo [])
(def foo (Foo. nil {:bar 1 :baz 2}))
В свете этого я обычно создаю функцию-конструктор, которая объединяется в некоторые значения по умолчанию (которые вы можете переопределить по своему усмотрению):
(defn make-foo [values-map]
(let [default-values {:bar 1 :baz 2}]
(Foo. nil (merge default-values values-map))))
(make-foo {:fiz 3 :bar 8})
=> #:user.Foo{:fiz 3, :bar 8, :baz 2}
Ответ 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.
Ответ 3
После того, как я задал тот же вопрос, я завершил загрузку 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 [email protected](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"}