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

Tom*_*ava 3 clojure

我目前正在使用一个功能

(def mymap {})

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

但由于这是有更多的参数,我想在调用functions2之前将其转换为地图.

(function2((assoc mymap (keyword var1) var1
               (keyword var2) var2
               (keyword var3) var3
               (keyword var4) var4
               (keyword var5) var5 ))
  )
Run Code Online (Sandbox Code Playgroud)

这是正确的方法吗?我们有更好的方法吗(在java中我们直接使用这种情况下的一些对象)

Ala*_*son 5

对于一般函数args,我总是按照从最大到最小的顺序排列,无论是大小还是"重要性"(有点主观).


但是,如果你有超过3个args,我更喜欢传递一个包含args和相应关键字名称的地图.

图珀洛的Clojure库有一些工具,使这个容易.该宏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})
Run Code Online (Sandbox Code Playgroud)

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")))))
Run Code Online (Sandbox Code Playgroud)

如果您嵌套在地图和/或矢量数据,你可以使用更强大destructrestruct工具.这是一个简短的例子(来自单元测试):

  (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}})))
Run Code Online (Sandbox Code Playgroud)

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

(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]}]))))))
Run Code Online (Sandbox Code Playgroud)

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

  (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])))
Run Code Online (Sandbox Code Playgroud)