clojure
Clojure förstörande
Sök…
Destrukturera en vektor
Så här kan du förstöra en vektor:
(def my-vec [1 2 3])
Därefter, exempelvis inom en let
blocket, kan du extrahera värden från vektorn mycket kortfattat på följande sätt:
(let [[x y] my-vec]
(println "first element:" x ", second element: " y))
;; first element: 1 , second element: 2
Destrukturera en karta
Så här kan du förstöra en karta:
(def my-map {:a 1 :b 2 :c 3})
Sedan, till exempel, inom ett låtblock kan du extrahera värden från kartan mycket kortfattat enligt följande:
(let [{x :a y :c} my-map]
(println ":a val:" x ", :c val: " y))
;; :a val: 1 , :c val: 3
Lägg märke till att värdena som extraheras i varje kartläggning är till vänster och knapparna de är associerade med till höger.
Om du vill förstöra värden på bindningar med samma namn som tangenterna kan du använda den här genvägen:
(let [{:keys [a c]} my-map]
(println ":a val:" a ", :c val: " c))
;; :a val: 1 , :c val: 3
Om dina nycklar är strängar kan du använda nästan samma struktur:
(let [{:strs [foo bar]} {"foo" 1 "bar" 2}]
(println "FOO:" foo "BAR: " bar ))
;; FOO: 1 BAR: 2
Och på liknande sätt för symboler:
(let [{:syms [foo bar]} {'foo 1 'bar 2}]
(println "FOO:" foo "BAR:" bar))
;; FOO: 1 BAR: 2
Om du vill förstöra en kapslad karta kan du bo boformer som förklaras ovan:
(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]
Förstör resterande element i en sekvens
Låt oss säga att du har en sådan vektor:
(def my-vec [1 2 3 4 5 6])
Och du vill extrahera de tre första elementen och få de återstående elementen som en sekvens. Detta kan göras på följande sätt:
(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)
Destrukturera kapslade vektorer
Du kan förstöra kapslade vektorer:
(def my-vec [[1 2] [3 4]])
(let [[[a b][c d]] my-vec]
(println a b c d))
;; 1 2 3 4
Destrukturera en karta med standardvärden
Ibland vill du förstöra nyckeln under en karta som kanske inte finns på kartan, men du vill ha ett standardvärde för det förstörda värdet. Du kan göra det på detta sätt:
(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
Förstörande params av en fn
Destructurling fungerar på många platser såväl som i param listan över en fn:
(defn my-func [[_ a b]] (+ a b)) (my-func [1 2 3]) ;= 5 (my-func (range 5)) ;= 3
Destrukturering fungerar också för & rest
konstruktionen i param listan:
(defn my-func2 [& [_ a b]] (+ a b)) (my-func2 1 2 3) ;= 5 (apply my-func2 (range 5)) ;= 3
Konvertera resten av en sekvens till en karta
Destrukturering ger dig också möjligheten att tolka en sekvens som en karta:
(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
Det är användbart för att definiera funktioner med namngivna parametrar :
(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
Översikt
Destrukturering låter dig extrahera data från olika objekt i olika variabler. I varje exempel nedan tilldelas varje variabel sin egen sträng ( a
= "a"
, b = "b"
, & c.)
Typ | Exempel | Värde på data / kommentar |
---|---|---|
vec | (let [[abc] data ...) | ["a" "b" "c"] |
kapslad vec | (let [[[ab] [cd]] data ...) | [["a" "b"] ["c" "d"]] |
map | (let [{a :ab :bc :c} data ...) | {:a "a" :b "b" :c "c"} |
- alternativ: | (let [{:keys [abc]} data ...) | När variabler namnges efter tangenterna. |
tips:
- Standardvärden kan anges med
:or
, annars är standardnil
- Använd
& rest
att lagra enseq
av extra värden irest
, annars ignoreras extravärdena - En vanlig och användbar användning av destruktion är för funktionsparametrar
- Du kan tilldela oönskade delar till en kasta-variabel (konventionellt:
_
)
Destrukturering och bindning till nycklarnas namn
Ibland när du förstör kartor vill du binda de förstörda värdena till deras respektive nyckelnamn. Beroende på datorns uppbyggnadsgrad, kan användningen av standardförstörningsschemat vara lite ordboken .
Låt oss säga, vi har en kartbaserad post som så:
(def john {:lastname "McCarthy" :firstname "John" :country "USA"})
vi skulle normalt förstöra det så:
(let [{lastname :lastname firstname :firstname country :country} john]
(str firstname " " lastname ", " country))
;;"John McCarthy, USA"
här är datastrukturen ganska enkel med bara 3 platser ( förnamn, efternamn, land ) men föreställ dig hur besvärligt det skulle vara om vi var tvungna att upprepa alla nyckelnamn två gånger för mer granulerad datastruktur (med väldigt fler slots än bara 3) .
I stället är ett bättre sätt att hantera detta genom att använda :keys
(eftersom våra nycklar är nyckelord här) och välja det nyckelnamn vi vill binda till så:
(let [{:keys [firstname lastname country]} john]
(str firstname " " lastname ", " country))
;;"John McCarthy, USA"
Samma intuitiva logik gäller för andra nyckeltyper som symboler (med :syms
) och vanliga gamla strängar (med :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"
Destrukturera och ge ett namn på det ursprungliga argumentvärdet
(defn print-some-items
[[a b :as xs]]
(println a)
(println b)
(println xs))
(print-some-items [2 3])
Det här exemplet skriver ut utgången
2
3
[2 3]
Argumentet är förstört och artiklarna 2
och 3
tilldelas symbolerna a
och b
. Det ursprungliga argumentet, hela vektorn [2 3]
, tilldelas också symbolen xs
.