Clojure Destructuring Tutorial and Cheat Sheet

When I try to write or read some Clojure code, every now and then I get stuck on some destructuring forms. It’s like a broken record. One moment I’m in the zone, then this thing hits me and I have to stop what I’m doing to try and grok what I’m looking at.

So I decided I’d write a little tutorial/cheatsheet for Clojure destructuring, both as an attempt to really grok it (I absorb stuff more quickly if I write it down), and as future reference for myself and others.

Below is the whole thing, copied from the original [gist][gist]. I’m planning on adding more (elaborate) examples and a section for compojure’s own destructuring forms. If you want to bookmark the cheat sheet, I recommend the gist since it has proper syntax highlighting and will be updated first.

Simply put, destructuring in Clojure is a way extract values from a datastructure and bind them to symbols, without having to explicitly traverse the datstructure. It allows for elegant and concise Clojure code.

Vectors 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 { % endhighlight % } 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] Optional arguments for functions With destructuring and the & rest form, you can specify optional arguments to functions. ( defn foo [ a b & [ x y z ]] ( 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