2015-07-25 2 views
1

Я определил запись с кучей полей - некоторые из них вычисляются, некоторые из которых не отображаются непосредственно в ключи в данных JSON, которые я глотаю , Я пишу для него заводскую функцию, но хочу иметь разумные значения по умолчанию/не найденные. Есть ли лучший способ, который накладывается на :or [field1 "" field2 "" field3 "" field4 ""...]? Я мог бы написать макрос, но я бы предпочел, если мне это не нужно.clojure same ": или" значение для всех ключей

+1

Почему '' или {...} 'не будет достаточно хорошим? Что квалифицирует что-то лучшее, чем это? – bsvingen

+0

«Слияние» может быть более явным, чем использование ': или' в деструктурировании, а' rename-keys' может помочь с разными именами ключей, но это трудно сказать, не видя полного кода – nberger

ответ

1

Существует три распространенных идиома для реализации значений по умолчанию в конструкторских функциях.

  1. :or destructoring

    Пример:

    (defn make-creature [{:keys [type name], :or {type :human 
                   name (str "unnamed-" (name type))}}] 
        ;; ... 
    ) 
    

    Это полезно, если вы хотите, чтобы указать значения по умолчанию рядный. В качестве бонуса он позволяет устанавливать привязки стиля let на карте :or, где kvs упорядочены в соответствии с вектором :keys.

  2. Слияния

    Пример:

    (def default-creature-spec {:type :human}) 
    
    (defn make-creature [spec] 
        (let [spec (merge default-creature-spec 
            spec)] 
         ;; .... 
        )) 
    

    Это полезно, если вы хотите, чтобы определить значения по умолчанию извне, создавать их во время выполнения и/или использовать их в другом месте.

  3. Простой or

    Пример:

    (defn make-creature [{:keys [type name]}] 
        (let [type (or type :human) 
         name (or name (str "unnamed-" (name type)))] 
        ;; ... 
        )) 
    

    Это так полезно, как :or destructoring, но только те значения по умолчанию вычисляются, которые действительно необходимы, т.е.. е. он должен использоваться в случаях, когда вычисление по умолчанию добавляет нежелательные служебные данные. (Я не знаю, почему :or оценивает все значения по умолчанию (как на Clojure 1.7), поэтому это обходное решение).

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, так и в clojurescript, его использование объясняется в «Программе Clojure от Chas Emerick, Brian Carper, Christophe Grand», и также упоминается in this thread во время обсуждения того, как получить ключи от записи. Итак, решать вам, стоит ли использовать его)

Смежные вопросы