Skip to content

Instantly share code, notes, and snippets.

@joey-coleman
Forked from john2x/00_destructuring.md
Created November 23, 2015 20:51
Show Gist options
  • Save joey-coleman/afb9f2a8517796b7f3f5 to your computer and use it in GitHub Desktop.
Save joey-coleman/afb9f2a8517796b7f3f5 to your computer and use it in GitHub Desktop.
Clojure Destructuring Tutorial and Cheat Sheet

Vectors

Vector destructuring is the simplest form. It is similar to Python's list unpacking feature, but much more powerful.

Syntax: [symbol another-symbol] ["value" "another-value"]

(def my-vector [:a :b :c :d])
(def my-nested-vector [:a :b :c :d [:x :y :z]])

(let [[a b c d] my-vector]
  (println a b c d))
;; => :a :b :c :d

(let [[a _ _ d [x y z]] my-nested-vector]
  (println a d x y z))
;; => :a :d :x :y :z

You don't have to match the full vector.

(let [[a b c] my-vector]
  (println a b c))
;; => :a :b :c

You can use & rest to bind the remaining part of the vector to rest.

(let [[a b & rest] my-vector]
  (println a b rest))
;; => :a :b (:c :d)

When a destructuring form "exceeds" a vector (i.e. there not enough items in the vector to bind to), the excess symbols will be bound to nil.

(let [[a b c d e f g] my-vector]
  (println a b c d e f g))
;; => :a :b :c :d nil nil nil

You can use :as some-symbol as the last two items in the destructuring form to bind the whole vector to some-symbol

(let [[:as all] my-vector]
  (println all))
;; => [:a :b :c :d]

(let [[a :as all] my-vector]
  (println a all))
;; => :a [:a :b :c :d]

(let [[a _ _ _ [x y z :as nested] :as all] my-nested-vector]
  (println a x y z nested all))
;; => :a :x :y :z [:x :y :z] [:a :b :c :d [:x :y :z]]

You can use both & rest and :as some-symbol.

(let [[a b & rest :as all] my-vector]
  (println a b rest all))
;; => :a :b (:c :d) [:a :b :c :d]

Function args usage:

(defn foo [a b & [x y z]]  ;; <= here we are using the `& rest` form, but at the same time we immediately destructure it
  (println a b x y z))
(foo :a :b) ;; => :a :b nil nil nil
(foo :a :b :x) ;; => :a :b :x nil nil
(foo :a :b :x :y :z) ;; => :a :b :x :y :z

Hashmaps

Hashmap destructuring is much more complicated, and can get quite verbose, but is much more powerful than vector destructuring.

Syntax: {symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}

(def my-hashmap {:a "A" :b "B" :c "C" :d "D"}) (def my-nested-hashmap {:a "A" :b "B" :c "C" :d "D" :q {:x "X" :y "Y" :z "Z"}})

(let [{a :a d :d} my-hashmap] (println a d)) ;; => A D

(let [{a :a b :b {x :x y :y} :q} my-nested-hashmap] (println a b x y)) ;; => A B X Y

Similar to vectors, if a key is not found in the map, the symbol will be bound to nil.

(let [{a :a not-found :not-found b :b :as all} my-hashmap] (println a not-found b all)) ;; => A nil B {:a "A" :b "B" :c "C" :d "D"}

You can provide an optional default value for these missing keys.

A

Shortcuts

Vectors + Hashmaps + Vectors...


Compojure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment