È possibile vedere cosa sta succedendo sotto le coperte chiamando il numero destructure
manualmente. Cominciamo con un esempio più semplice:.
user> (destructure ['{foo :foo} {:foo 42}])
[map__26147 {:foo 42}
map__26147 (if (clojure.core/seq? map__26147)
(clojure.lang.PersistentHashMap/create
(clojure.core/seq map__26147))
map__26147)
foo (clojure.core/get map__26147 :foo)]
Ciò corrisponde a (let [{foo :foo} {:foo 42}] ...)
(come si può verificare con (macroexpand-1 '(let [{foo :foo} {:foo 42}] ...))
La seconda linea di uscita è il bit importante Una mappa forma vincolante può funzionare in due modi:. Se il valore essendo legato è un seq, il seq sarà 'versato' in una mappa hash (come se fosse (apply hash-map the-seq)
. Altrimenti, si presume che il valore sia associativo e usato direttamente.La funzione seq 'pouring' è stata aggiunta in this commit.
Proviamo:
user> (let [{foo :foo} {:foo 42}] foo)
42
user> (let [{foo :foo} (list :foo 42)] foo)
42
user> (let [{foo :foo} (apply hash-map (list :foo 42))] foo)
42
Nel primo caso, il valore non è un seq, quindi viene utilizzato direttamente. Nel secondo caso, una lista è un seq, quindi viene "versato" in una mappa hash prima di essere associato a {foo :foo}
. Il terzo caso mostra che questo versamento è semanticamente equivalente a (apply hash-map the-seq)
.
Ora diamo un'occhiata a qualcosa come il tuo esempio:
user> (destructure '[[& {:keys [foo bar]}] args])
[vec__26204 args
map__26205 (clojure.core/nthnext vec__26204 0)
map__26205 (if (clojure.core/seq? map__26205)
(clojure.lang.PersistentHashMap/create
(clojure.core/seq map__26205))
map__26205)
bar (clojure.core/get map__26205 :bar)
foo (clojure.core/get map__26205 :foo)]
Il bit nthnext
è dal &
- in questo caso, perché non ci sono parametri fissi prima della &
, abbiamo un (nthnext vec# 0)
, che ammonta a basta convertire args
in un seq (se necessario). Quindi abbiamo la mappa destrutturante come sopra. Poiché il &
garantisce che abbiamo un seq, il caso speciale seq per la destrutturazione delle mappe verrà sempre attivato e gli argomenti verranno sempre "riversati" in una mappa hash prima di essere associati al modulo della mappa.
Nel caso in cui il rapporto tra questo esempio e la vostra fn originale non è chiaro, prendere in considerazione:
user> (macroexpand-1 '(fn [& {:keys [foo bar]}]))
(fn* ([& p__26214] (clojure.core/let [{:keys [foo bar]} p__26214])))
"Il vettore in forma mappa destrutturazione è solo la sintassi" - anzi, un elenco funzionerà altrettanto bene qui. – Alex