clojure
Деструктурирование Clojure
Поиск…
Уничтожение вектора
Вот как вы можете разрушить вектор:
(def my-vec [1 2 3])
Затем, например, в блоке let
вы можете извлечь значения из вектора очень кратко следующим образом:
(let [[x y] my-vec]
(println "first element:" x ", second element: " y))
;; first element: 1 , second element: 2
Уничтожение карты
Вот как вы можете разрушить карту:
(def my-map {:a 1 :b 2 :c 3})
Затем, например, в блоке let вы можете извлекать значения с карты очень кратко следующим образом:
(let [{x :a y :c} my-map]
(println ":a val:" x ", :c val: " y))
;; :a val: 1 , :c val: 3
Обратите внимание, что значения, извлекаемые в каждом сопоставлении, находятся слева, а ключи, с которыми они связаны, находятся справа.
Если вы хотите разрушить значения привязок с теми же именами, что и ключи, вы можете использовать этот ярлык:
(let [{:keys [a c]} my-map]
(println ":a val:" a ", :c val: " c))
;; :a val: 1 , :c val: 3
Если ваши клавиши являются строками, вы можете использовать почти ту же структуру:
(let [{:strs [foo bar]} {"foo" 1 "bar" 2}]
(println "FOO:" foo "BAR: " bar ))
;; FOO: 1 BAR: 2
И аналогично для символов:
(let [{:syms [foo bar]} {'foo 1 'bar 2}]
(println "FOO:" foo "BAR:" bar))
;; FOO: 1 BAR: 2
Если вы хотите разрушить вложенную карту, вы можете вложить пояснительные формы, описанные выше:
(def data
{:foo {:a 1
:b 2}
:bar {:a 10
:b 20}})
(let [{{:keys [a b]} :foo
{a2 :a b2 :b} :bar} data]
[a b a2 b2])
;; => [1 2 10 20]
Уничтожение оставшихся элементов в последовательности
Предположим, у вас есть такой вектор:
(def my-vec [1 2 3 4 5 6])
И вы хотите извлечь первые 3 элемента и получить оставшиеся элементы в виде последовательности. Это можно сделать следующим образом:
(let [[x y z & remaining] my-vec]
(println "first:" x ", second:" y "third:" z "rest:" remaining))
;= first: 1 , second: 2 third: 3 rest: (4 5 6)
Уничтожение вложенных векторов
Вы можете разрушить вложенные векторы:
(def my-vec [[1 2] [3 4]])
(let [[[a b][c d]] my-vec]
(println a b c d))
;; 1 2 3 4
Уничтожение карты со значениями по умолчанию
Иногда вы хотите разрушить ключ под картой, которая может отсутствовать на карте, но вам нужно значение по умолчанию для деструктурированного значения. Вы можете сделать это следующим образом:
(def my-map {:a 3 :b 4}) (let [{a :a b :b :keys [c d] :or {a 1 c 2}} my-map] (println a b c d)) ;= 3 4 2 nil
Деструктурирующие параметры fn
Деструктурирование работает во многих местах, а также в списке параметров fn:
(defn my-func [[_ a b]] (+ a b)) (my-func [1 2 3]) ;= 5 (my-func (range 5)) ;= 3
Деструктурирование также работает для конструкции & rest
в списке параметров:
(defn my-func2 [& [_ a b]] (+ a b)) (my-func2 1 2 3) ;= 5 (apply my-func2 (range 5)) ;= 3
Преобразование остальной части последовательности в карту
Разрушение также дает вам возможность интерпретировать последовательность как карту:
(def my-vec [:a 1 :b 2])
(def my-lst '("smthg else" :c 3 :d 4))
(let [[& {:keys [a b]}] my-vec
[s & {:keys [c d]} my-lst]
(+ a b c d)) ;= 10
Он полезен для определения функций с именованными параметрами :
(defn my-func [a b & {:keys [c d] :or {c 3 d 4}}]
(println a b c d))
(my-func 1 2) ;= 1 2 3 4
(my-func 3 4 :c 5 :d 6) ;= 3 4 5 6
обзор
Разрушение позволяет извлекать данные из различных объектов в отдельные переменные. В каждом примере ниже каждая переменная присваивается собственной строке ( a
= "a"
, b = "b"
, & c.)
Тип | пример | Значение data / комментариев |
---|---|---|
vec | (let [[abc] data ...) | ["a" "b" "c"] |
вложенный vec | (let [[[ab] [cd]] data ...) | [["a" "b"] ["c" "d"]] |
map | (let [{a :ab :bc :c} data ...) | {:a "a" :b "b" :c "c"} |
- альтернатива: | (let [{:keys [abc]} data ...) | Когда переменные называются после клавиш. |
Подсказки:
- Значения по умолчанию могут быть предоставлены с использованием
:or
, в противном случае по умолчанию используется значениеnil
- Используйте
& rest
для храненияseq
любых дополнительных значений в состоянииrest
, иначе дополнительные значения игнорируются - Обычное и полезное использование деструктурирования - это параметры функции
- Вы можете назначить нежелательные части переменной выброса (условно:
_
)
Уничтожение и привязка к имени ключа
Иногда при деструктурировании карт вы хотите привязать деструктурированные значения к их соответствующему имени ключа. В зависимости от гранулярности структуры данных использование стандартной схемы деструктурирования может быть немного подробным .
Скажем, у нас есть запись на основе карты:
(def john {:lastname "McCarthy" :firstname "John" :country "USA"})
мы обычно разрушаем его так:
(let [{lastname :lastname firstname :firstname country :country} john]
(str firstname " " lastname ", " country))
;;"John McCarthy, USA"
здесь структура данных довольно проста только с тремя слотами (имя , фамилия, страна ), но представьте, насколько это было бы громоздко, если бы нам пришлось повторять все имена ключей дважды для более подробной структуры данных (имея больше слотов, чем просто 3) ,
Вместо этого лучший способ справиться с этим - с помощью :keys
(поскольку наши ключи являются ключевыми словами здесь) и выбора имени ключа, которое мы хотели бы привязать так:
(let [{:keys [firstname lastname country]} john]
(str firstname " " lastname ", " country))
;;"John McCarthy, USA"
Такая же интуитивная логика применяется для других типов ключей, таких как символы (с использованием :syms
) и простых старых строк (с использованием :strs
)
;; using strings as keys
(def john {"lastname" "McCarthy" "firstname" "John" "country" "USA"})
;;#'user/john
;; destructuring string-keyed map
(let [{:strs [lastname firstname country]} john]
(str firstname " " lastname ", " country))
;;"John McCarthy, USA"
;; using symbols as keys
(def john {'lastname "McCarthy" 'firstname "John" 'country "USA"})
;; destructuring symbol-keyed map
(let [{:syms [lastname firstname country]} john]
(str firstname " " lastname ", " country))
;;"John McCarthy, USA"
Деструктурирование и присвоение имени исходному значению аргумента
(defn print-some-items
[[a b :as xs]]
(println a)
(println b)
(println xs))
(print-some-items [2 3])
В этом примере выводится вывод
2
3
[2 3]
Аргумент деструктурирован, а элементы 2
и 3
присваиваются символам a
и b
. Исходный аргумент, весь вектор [2 3]
, также присваивается символу xs
.