Reputation: 9032
I'm a Java and learning clojure.
What is exactly destructuring in clojure?
I can see this blog saying:
The simplest example of destructuring is assigning the values of a vector.
user=> (def point [5 7])
#'user/point
user=> (let [[x y] point]
(println "x:" x "y:" y))
x: 5 y: 7
what he meant by assigning the values of a vector
? Whats the real use of it?
Thanks in advance
Upvotes: 6
Views: 247
Reputation: 83
The term "Destructuring" sounds heavier than it is.
It's like visually matching shapes to shapes. For example:
(def nums [1 2 3 4 5 6])
(let [[a b c & others] nums]
;; do something
)
Imagine the effect of the let binding as:
1 2 3 4 5 6
| | | ( )
v v v v
[a b c & others]
;; Now we can use a, b, c, others, and of course nums,
;; inside the let binding:
user=> (let [[a b c & others] nums]
(println a)
(println b)
(println c)
(println others)
(println nums))
1
2
3
(4 5 6)
[1 2 3 4 5 6]
The goal is to concisely name items of a collection, for use inside the scope of a let binding or function (i.e. within a "lexical scope").
Why "concise"? Well, without destructuring, the let binding would look like this:
(let [a (nth nums 0) ;; or (first nums)
b (nth nums 1) ;; or (second nums)
c (nth nums 2)
others (drop 3 nums)]
;; do something
)
This illustrates the basic idea. There are many details (ifs and buts, and dos and don'ts), and it's worth reading further, in depth. Here are a few resources that explain more, with examples:
My personal favourite: Jay Fields's post on Clojure Destructuring: http://blog.jayfields.com/2010/07/clojure-destructuring.html
A gentle introduction to destructuring, from Braveclojure: http://www.braveclojure.com/do-things/#3_3_3__Destructuring
Upvotes: 2
Reputation: 4643
It means making a picture of the structure of some data with symbols
((fn [[d [s [_ _]]]]
(apply str (concat (take 2 (name d)) (butlast (name s)) (drop 7 (name d))) ))
'(describing (structure (of data))))
=> "destructuring"
((fn [[d e _ _ _ _ _ i n g _ _ _ _ _ s t r u c t u r e & etc]]
[d e s t r u c t u r i n g]) "describing the structure of data")
=> [\d \e \s \t \r \u \c \t \u \r \i \n \g]
Paste those ^ examples into a REPL & play around with them to see how it works.
Upvotes: 2
Reputation: 13473
Destructuring binds a pattern of names to a complex object by binding each name to the corresponding part of the object.
To bind to a sequence, you present a vector of names. For example ...
(let [[x y] (list 5 7)] ... )
... is equivalent to
(let [x 5, y 7] ... )
To bind to a map or to a vector by index lookup, you present a map of name-to-key pairs. For example ...
(let [{x 0, y 1} [5 7]] ... )
... is equivalent to both of the above.
As others have mentioned, you can find a full description of this powerful mechanism here.
Upvotes: 0
Reputation: 5017
Destructuring is a convenience feature which allows local bindings (not variables!) to be created easily by taking apart complex data structures (seq-ables like vectors, or associatives like hash-maps), as it is described here.
Take the following example:
(let [v [1 2 3 4 5 6]
v_0 (first v)
v_1 (nth v 1)
v_rest (drop 2 v)
m {:a 1 :b 2}
m_a (get m :a)
m_b (get m :b)
m_default (get m :c "DEFAULT")]
(println v, v_0, v_1, v_rest, m, m_a, m_b, m_default))
Then the above code can be simplified using destructuring bindings like the following:
(let [[v_0 v_1 & v_rest :as v]
[1 2 3 4 5 6]
{m_a :a m_b :b m_default :c :or {m_default "DEFAULT"} :as m}
{:a 1 :b 2}]
(println v, v_0, v_1, v_rest, m, m_a, m_b, m_default))
Destructuring patterns can be used in let
bindings and function parameters (fn
, defn
, letfn
, etc.), and also in macros to return let
bindings containing such destructuring patterns.
One important usage to note is with the if-let
and when-let
macros. The if
statement is always evaluated on the whole form, even if the destructured bindings themselves evaluate to nil
:
(if-let [{:keys [a b]}
{:c 1 :d 2}]
(println a b)
(println "Not this one"))
Upvotes: 0
Reputation: 4748
its used to name components of a data structure, and get their values.
Say you want to have a "person" structure. In java, you would go all the way to create a class with constructors, getters and setters for the various fields, such as name, age, height etc.
In Clojure you could skip the "ceremony" and simply have a vector with 3 slots, first for name, than for age and last for height. Now you could simply name these "components" and get their values, like so:
(def person ["Fred" 30 180])
(let [[name age height] person]
(println name age height)) ;; will print: Fred 30 180
p.s - there are better ways to make a "person" in clojure (such as records etc), this is just an example to understand what destructuring does.
Upvotes: 0
Reputation: 780974
point
is a variable that contains a vector of values. [x y]
is a vector of variable names.
When you assign point
to [x y]
, destructuring means that the variables each get assigned the corresponding element in the value.
This is just a simpler way of writing:
(let [x (nth point 0) y (nth point 1)]
(println "x:" x "y:" y))
See Clojure let binding forms for another way to use destructuring.
Upvotes: 2