2011-04-12 269 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"} 
相關問題