Для аргументов общей функции я всегда иду по порядку от самого большого к наименьшему, либо по размеру, либо по «важности» (несколько субъективно).
Однако, еслиу вас есть более 3 аргументов , я предпочитаю передавать карту, содержащую аргументы и соответствующие имена ключевых слов.
В библиотеке Tupelo 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})
Макрос 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")))))
Если у вас есть вложенные данные в картах и / или векторах, вы можете использовать более мощные инструменты destruct
и restruct
.Вот краткий пример ( из модульных тестов ):
(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])))