Clojure/Script如何构建含默认值的解构Map?无需重复键名
解决Clojure/Script中带默认值的Map解构与构建问题
你碰到的核心问题很明确:原代码里的:or解构只是给单个变量设置默认值,但:as prompt捕获的还是传入的原始参数Map——如果调用时没传某个键,这个键不会自动出现在prompt里。要实现“自动填充默认值且不重复键名”的需求,我们可以用更直接的merge方式来处理:
最优方案:用merge合并默认值与传入参数
这种方式既避免重复键名,又能确保最终的prompt包含所有必填键,没传的自动用默认值:
(re-frame/reg-event-db :open-prompt (fn [db [_ params]] (let [;; 定义所有默认值,只写一次键名 defaults {:title "Confirm" :text "Are you sure?" :label-yes "Ok" :label-no "Cancel"} ;; 合并:传入的参数会覆盖默认值,没传的保留默认 prompt (merge defaults params)] (-> db (update :state conj :modal-prompt) (assoc :prompt prompt)))))
为什么这个方案好用?
- 键名只在
defaults里定义一次,完全符合你“无需重复键名”的要求 merge的逻辑清晰:传入的参数优先级更高,会覆盖对应的默认值;没传的键直接从defaults继承- 最终的
prompt一定会包含title、text、label-yes、label-no四个键,不会缺失
原代码的问题解析
你原来的写法里,:or的作用是给解构出来的单个变量赋值默认值,而不是修改原始的参数Map:
;; 原代码的解构部分 {title :title text :text label-yes :label-yes label-no :label-no :or {title "Confirm" text "Are you sure?" label-yes "Ok" label-no "Cancel"} :as prompt}
这里的title、text等变量会拿到默认值,但:as prompt捕获的还是调用时传入的原始Map——如果调用时没传:label-yes,prompt里就不会有这个键,哪怕label-yes变量是默认值。因为你最后把prompt直接存入db,所以才会出现缺键的情况。
备选方案(不推荐,会重复键名)
如果一定要在解构阶段处理,只能手动用解构后的变量重新构建Map,但这样会重复键名,不符合你的需求,仅作参考:
(re-frame/reg-event-db :open-prompt (fn [db [_ {title :title text :text label-yes :label-yes label-no :label-no :or {title "Confirm" text "Are you sure?" label-yes "Ok" label-no "Cancel"}}]] (let [prompt {:title title :text text :label-yes label-yes :label-no label-no}] (-> db (update :state conj :modal-prompt) (assoc :prompt prompt)))))
内容的提问来源于stack exchange,提问作者mike3996
相关产品推荐
相关产品推荐

