Clojure:从地图动态创建函数 - 宏的时间?

diz*_*tar 6 macros refactoring clojure hiccup noir

我有一个像这样开始的函数:

(defn data-one [suser]
    (def suser-first-name
       (select db/firstNames
            (fields :firstname)
            (where {:username suser})))
    (def suser-middle-name
        (select db/middleNames
            (fields :middlename)
            (where {:username suser})))
    (def suser-last-name
         (select db/middleNames
             (fields :lastname)
             (where {:username suser})))
    ;; And it just continues on and on...
        )
Run Code Online (Sandbox Code Playgroud)

当然,我根本不喜欢这个.我在代码库的许多方面都重复了这种模式,我想概括一下.

所以,我想出了以下内容:

(def data-input {:one '[suser-first-name db/firstNames :firstname] 
                      '[suser-middle-name db/middleNames :middlename]
                      '[suser-last-name db/lastNames :lastname]})

(defpartial data-build [data-item suser]
    ;; data-item takes the arg :one in this case
     `(def (data-input data-item)
        (select (data-input data-item)
            (fields (data-input data-item))
            (where {:username suser}))))
Run Code Online (Sandbox Code Playgroud)

这里有几个问题:

- 我如何解构数据输入,以便在x未知时创建x函数,即.以下值:one是未知的,并且数据输入中的键数量是未知的.

- 我认为现在是创建一个宏的时候了,但我以前从未构建过宏,所以我对这个想法犹豫不决.

并且为了给出一些上下文,函数必须返回要解构的值,但我认为一旦我解决了这个问题,将所有这些概括为一般是可行的:

(defpage "/page-one" []
    (let [suser (sesh/get :username)]       
    (data-one suser)
        [:p "Firat Name: " 
            [:i (let [[{fname :firstname}] suser-first-name]
                (format "%s" fname))]
        [:p "Middle Name: "  
            [:i (let [[{mname :emptype}] suser-middle-name]
                (format "%s" mname))]
        [:p "Last Name: " 
            [:i (let [[{lname :months}] suser-last-name]
                    (format "%s" lname))]]))
Run Code Online (Sandbox Code Playgroud)

mik*_*era 5

一些建议:

  • def在一个函数内部真的很讨厌 - 你正在改变全局环境,并且它可能导致各种并发问题.我建议将结果存储在地图中.
  • 并不需要一个宏在这里-所有数据取的可以相对容易地在函数中完成

因此我会建议:

(def data-input [[:suser-first-name db/firstNames :firstname] 
                 [:suser-middle-name db/middleNames :middlename]
                 [:suser-last-name db/lastNames :lastname]])

(def data-build [data-input suser]
  (loop [output {}
         items (seq data-input)]
    (if items
      (recur
        (let [[kw db fieldname] (first items)]
          (assoc output kw (select db (fields fieldname) (where {:username suser})))) 
        (next items))
      output)))
Run Code Online (Sandbox Code Playgroud)

没有测试,因为我没有你的数据库设置 - 但希望这能让你知道如何在没有宏或可变全局变量的情况下做到这一点!