Destructuring in Venice is a powerful feature that allows you to easily extract values from data structures (like lists, vectors, maps, and sequences) and bind them to variables. This makes your code more readable and concise by reducing the need for explicit indexing or lookups.
Sequential destructuring breaks up a sequential data structure as a Venice list or vector within a let binding
(do
(let [[x y z] [1 2 3]]
(println x y z))
;=> 1 2 3
(let [[x y z] '(1 2 3)]
(println x y z))
;=> 1 2 3
(let [[k v] (map-entry "a" 100)]
(println k v))
;=> "a" 100
;; for strings, the elements are destructured by character.
(let [[x y z] "abc"]
(println x y z))
;=> a b c
)
or within function parameters
(do
(defn position [[x y]]
(println "x:" x "y:" y))
(position [1 2]) ;=> x: 1 y: 2
)
The destructured collection must not be of same size as the number of binding names
(do
(let [[a b c d e f] '(1 2 3)]
(println a b c d e f))
;=> 1 2 3 nil nil nil
(let [[a b c] '(1 2 3 4 5 6 7 8 9)]
(println a b c))
;=> 1 2 3
)
(do
(let [[a b c & z] '(1 2 3 4 5 6 7 8 9)]
(println a b c z))
;=> 1 2 3 (4 5 6 7 8 9)
(let [[a _ b _ c & z] '(1 2 3 4 5 6 7 8 9)]
(println a b c z))
;=> 1 3 5 (6 7 8 9)
)
(do
(let [[a b c & z :as all] '(1 2 3 4 5 6 7 8 9)]
(println a b c z all))
;=> 1 2 3 (4 5 6 7 8 9) (1 2 3 4 5 6 7 8 9)
)
(do
(def line [[5 10] [10 20]])
(let [[[x1 y1][x2 y2]] line]
(printf "Line from (%d,%d) to (%d,%d)%n" x1 y1 x2 y2))
;=> "Line from (5,10) to (10,20)"
)
:as
or &
can be used at any level
(do
(def line [[5 10] [10 20]])
(let [[[a b :as group1] [c d :as group2]] line]
(println a b group1)
(println c d group2)))
;=> 5 10 [5 10]
;=> 10 20 [10 20])
(do
(let [[x y & z] (lazy-seq 1 inc)]
(println x y (doall (take 5 z)))))
;=> 1 2 (3 4 5 6 7)
(do
(let [[x _ y _ z] (lazy-seq 1 inc)]
(println x y z)))
;=> 1 3 5
Destructuring can be used directly in function parameters, making it easy to pass and work with complex data structures.
(do
(defn sum [[x y]]
(println "Sum: " (+ x y)))
(sum [1 2]))
Associative destructuring breaks up an associative (key/value) data structure as a Venice map within a let binding.
(do
(let [{a :a, b :b, c :c} {:a "A" :b "B" :d "D"}]
(println a b c))
; => A B nil
)
(do
(def map_keyword {:a "A" :b "B" :c 3 :d 4})
(def map_strings {"a" "A" "b" "B" "c" 3 "d" 4})
(let [{:keys [a b c]} map_keyword]
(println a b c))
; => A B 3
(let [{:strs [a b c]} map_strings]
(println a b c))
; => A B 3
)
(do
(def map_keyword {:a "A" :b "B" :c 3 :d 4})
(let [{:keys [a b c] :as all} map_keyword]
(println a b c all))
; => A B 3 {:a A :b B :c 3 :d 4}
)
(do
(defn configure [options]
(let [{:keys [port debug verbose] :or {port 8000, debug false, verbose false}} options]
(println "port =" port " debug =" debug " verbose =" verbose)))
;=> port 8000, debug false, verbose false
(configure {:debug true})
)
Associative destructuring can be nested and combined with sequential destructuring
(do
(def users
{:peter {:role "clerk"
:branch "Zurich"
:age 40}
:magda {:role "head of HR"
:branch "Bern"
:age 45}
:kurt {:role "assistant"
:branch "Lucerne"
:age 32}})
(let [{{:keys [role branch]} :peter} users]
(println "Peter is a" role "located at" branch))
;=> Peter is a clerk located at Zurich
)
Destructuring can be used directly in function parameters, making it easy to pass and work with complex data structures.
(do
(defn greet [{:keys [name age]}]
(println "Hello," name "you are" age "years old."))
(greet {:name "Charlie" :age 25}))