2011-04-12 158 views

回答

10

当你构建它虽然扩展地图你可以通过初始值,达到创纪录很容易:

(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} 
20

使用构造函数。

(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。

+0

链接,解释了如何使用*的:钥匙*和*:或* http://stuartsierra.com/2010/01/15/关键字参数在clojure – leeor 2015-08-09 21:36:48

+0

人们也可以利用'map-> Foo'和/或' - > Foo'就像这样(defn make-foo [&args](map-> Foo(into args {:a 5 :b 1:c 7}))(make-foo {:b 3})' - 它节省了一些解构 – birdspider 2016-07-04 15:19:55

1

有了同样的问题后,我最终使用宏将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"} 
相关问题