In Clojure you can apply destructuring within either a let
binding list; function parameter list or even a macro.
A simple example would be:
(def coords [5 7]) ; define a symbol "coords" that points to a vector [5 7]
(let [[x y] coords] (println "x:" x "y:" y))
; => x: 5 y: 7
Another simple example (this time using the &
rest operator) would be:
(def indexes [1 2 3])
(let [[x & more] indexes] (println "x:" x "more:" more))
; => x: 1 more: (2 3)
A complex example (which utilises :as e
to assign the entire item being destructured into e
):
(def indexes [1 2 3 4 5 6 7])
(let [[a b c & d :as e] indexes]
[a b c d e])
; => [1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]]
Although possible to do nested destructuring, it is advised not to nest as it can become too complex:
(def nested [[1 2][3 4]])
(let [[[x1 y1][x2 y2]] nested]
[x1 x2 y1 y2])
; => [1 3 2 4]
Here is an example that uses :or
to provide default values for keys that can't be found in the data being destructured (you'll notice that the b
key wasn't provided and so we received the default value of 22
instead):
(def a-map {:a 1 :c 3})
(let [{a :a, b :b, c :c, :as original-data :or {a 11 b 22 c 33}} a-map]
[a b c original-data])
; => [1 22 3 {:a 1, :c 3}]
In the following example we see the use of :keys
as a shortcut way of not having to redefine the same keys ourselves (typically when destructuring data you'll end up saying something like "give me the value for key 'a' and just put it in this other place called 'a'" - so Clojure provides a shortcut for that). This example also demonstrates what happens if no default is provided:
(def a-map {:a 1 :c 3})
(let [{:keys [a b c]} a-map]
[a b c])
; => [1 nil 3]
Nested map destructuring (whatever the type is - in this example a map - use that syntax to delve deeper into the structure):
(def test {:params {:foo "bar" :baz "qux"}})
(let [{{foo :foo} :params} test]
(prn foo))