Clojure编码标准-带有许多参数的调用函数

时间:2019-02-07 22:40:52

标签: clojure

我正在使用函数

(def mymap {})

(defn function1 [var1 var2 var3 var4 var5]
  ;calls another functions with all variables.
  (function2 var1 var2 var3 var4 var5)
)

但是由于它具有更多参数,因此我想在调用function2之前将其转换为映射。

(function2((assoc mymap (keyword var1) var1
               (keyword var2) var2
               (keyword var3) var3
               (keyword var4) var4
               (keyword var5) var5 ))
  )

这是正确的方法吗?我们是否有更好的方法来做到这一点(在Java中,在这种情况下我们不使用某些对象)

1 个答案:

答案 0 :(得分:5)

对于一般函数args,我总是按从大到小的顺序排列,  大小或“重要性”(有点主观)。


但是,如果您有3个以上的参数 ,我希望传递包含参数和适当的关键字名称的映射。

Tupelo Clojure library有一些工具可以简化这一过程。宏vals->map采用多个变量名,并构造一个从(关键字化的)变量名到其值的映射,例如:

  (let [ctx (let [a 1
                  b 2
                  c 3
                  d 4
                  e 5]
              (t/vals->map a b c d e))]
    (is= ctx {:a 1 :b 2 :c 3 :d 4 :e 5})

with-map-vals进行相反的操作,将映射值解构为为其键命名的局部变量。它类似于Clojure :keys的解构,但以(IMHO)更自然的形式:

    (let [{:keys [a b c d e]} ctx]    ; Clojure destructing syntax
      (is= [a b c d e] [1 2 3 4 5]))

    (t/with-map-vals ctx [a b c d e]
      (is= [a b c d e] [1 2 3 4 5])
      (is= 15 (+ a b c d e)))

    (t/with-map-vals ctx [b a d c e]  ; order doesn't matter
      (is= [a b c d e] [1 2 3 4 5])
      (is= 15 (+ a b c d e)))

    (t/with-map-vals ctx [b a d]      ; can ignore stuff you don't care about
      (is= [d a b] [4 1 2]))

    (throws?
      (t/with-map-vals ctx [a b z]    ; throws if key doesn't exist
        (println "won't ever get here")))))

如果您在地图和/或矢量中嵌套了数据 ,则可以使用功能更强大的destructrestruct工具。这是一个简短的示例(from the unit tests):

  (let [info  {:a 1
               :b {:c 3
                   :d 4}}
        mania {:x 6
               :y {:w 333
                   :z 666}}]

    (t/it-> (t/destruct [info {:a ?
                               :b {:c ?
                                   :d ?}}
                         mania {:y {:z ?}}] ; can ignore unwanted keys like :x
              (let [a (+ 100 a)
                    c (+ 100 c)
                    d z
                    z 777]
                (restruct-all)))
      (t/with-map-vals it [info mania]
        (is= info {:a 101, :b {:c 103, :d 666}})
        (is= mania {:x 6, :y {:w 333, :z 777}})))

如您所见,问号?将导致相应的值被分解为以相应关键字命名的变量。也可以像这样创建显式变量名:

(dotest
  (let [info  {:a 777
               :b [2 3 4]}
        mania [{:a 11} {:b 22} {:c [7 8 9]}]]
    (let [z ::dummy]
      (t/it-> (t/destruct [info {:a z
                                 :b [d e f]}
                           mania [{:a ?} BBB {:c clutter}]]
                (let [clutter (mapv inc clutter)
                      BBB     {:BBB 33}
                      z       77
                      d       (+ 7 d)]
                  (restruct-all)))
        (t/with-map-vals it [info mania]
          (is= info {:a 77, :b [9 3 4]})
          (is= mania [{:a 11} {:BBB 33} {:c [8 9 10]}]))))))

它也适用于混合地图和矢量:

  (let [data {:a [{:b 2}
                  {:c 3}
                  [7 8 9]]} ]
    (t/destruct [data {:a [{:b p}
                           {:c q}
                           [r s t]]} ]
      (is= [2 3 7 8 9] [p q r s t])))