Sök…


Syntax

  • '()()
  • '(1 2 3 4 5)(1 2 3 4 5)
  • '(1 foo 2 bar 3)(1 'foo 2 'bar 3)
  • ( list 1 2 3 4 5)(1 2 3 4 5)
  • ( list* [1 2 3 4 5])(1 2 3 4 5)
  • [][]
  • [1 2 3 4 5][1 2 3 4 5]
  • ( vector 1 2 3 4 5)[1 2 3 4 5]
  • ( vec '(1 2 3 4 5))[1 2 3 4 5]
  • {} => {}
  • {:keyA 1 :keyB 2}{:keyA 1 :keyB 2}
  • {:keyA 1, :keyB 2}{:keyA 1 :keyB 2}
  • ( hash-map :keyA 1 :keyB 2){:keyA 1 :keyB 2}
  • ( sorted-map 5 "five" 1 "one"){1 "one" 5 "five"} (poster sorteras efter tangent när de används som en sekvens)
  • #{}#{}
  • #{1 2 3 4 5}#{4 3 2 5 1} (oordnad)
  • ( hash-set 1 2 3 4 5)#{2 5 4 1 3} (oordnad)
  • ( sorted-set 2 5 4 3 1)#{1 2 3 4 5}

samlingar

Alla inbyggda Clojure-samlingar är oföränderliga och heterogena, har bokstavlig syntax och stöder conj , count och seq funktioner.

  • conj returnerar en ny samling som motsvarar en befintlig samling med en artikel "tillagd", antingen i "konstant" eller logaritmisk tid. Vad exakt detta betyder beror på samlingen.
  • count ger antalet objekt i en samling i konstant tid.
  • seq returnerar nil för en tom samling, eller en sekvens av objekt för en icke-tom samling, i konstant tid.

listor

En lista betecknas med parenteser:

()
;;=> ()

En Clojure-lista är en enskilt länkad lista . conj "förenar" ett nytt element i samlingen på den mest effektiva platsen. För listor är detta i början:

(conj () :foo)
;;=> (:foo)

(conj (conj () :bar) :foo)
;;=> (:foo :bar)

Till skillnad från andra samlingar utvärderas icke-tomma listor som samtal till speciella formulär, makron eller funktioner när de utvärderas. Därför, medan (:foo) är den bokstavliga representationen av listan som innehåller :foo som dess enda objekt, kommer utvärdering (:foo) i en REPL att leda till att en IllegalArgumentException kastas eftersom ett sökord inte kan åberopas som en null funktion .

(:foo)
;; java.lang.IllegalArgumentException: Wrong number of args passed to keyword: :foo

För att förhindra att Clojure utvärderar en icke-tom lista kan du quote den:

'(:foo)
;;=> (:foo)

'(:foo :bar)
;;=> (:foo :bar)

Tyvärr gör detta att elementen inte utvärderas:

(+ 1 1)
;;=> 2

'(1 (+ 1 1) 3)
;;=> (1 (+ 1 1) 3)

Av detta skäl vill du vanligtvis använda list , en variadisk funktion som utvärderar alla dess argument och använder dessa resultat för att konstruera en lista:

(list)
;;=> ()

(list :foo)
;;=> (:foo)

(list :foo :bar)
;;=> (:foo :bar)

(list 1 (+ 1 1) 3)
;;=> (1 2 3)

count ger antalet objekt i konstant tid:

(count ())
;;=> 0

(count (conj () :foo))
;;=> 1

(count '(:foo :bar))
;;=> 2

Du kan testa om något är en lista med list? predikat:

(list? ())
;;=> true

(list? '(:foo :bar))
;;=> true

(list? nil)
;;=> false

(list? 42)
;;=> false

(list? :foo)
;;=> false

Du kan få det första elementet i en lista med peek :

(peek ())
;;=> nil

(peek '(:foo))
;;=> :foo

(peek '(:foo :bar))
;;=> :foo

Du kan få en ny lista utan det första elementet med pop :

(pop '(:foo))
;;=> ()

(pop '(:foo :bar))
;;=> (:bar)

Observera att om du försöker pop en tom lista får du en IllegalStateException :

(pop ())
;; java.lang.IllegalStateException: Can't pop empty list

Slutligen är alla listor sekvenser, så du kan göra allt med en lista som du kan göra med någon annan sekvens. I själva verket, med undantag för den tomma listan, kalla seq på en lista returnerar exakt samma objekt:

(seq ())
;;=> nil

(seq '(:foo))
;;=> (:foo)

(seq '(:foo :bar))
;;=> (:foo :bar)

(let [x '(:foo :bar)]
  (identical? x (seq x)))
;;=> true

sekvenser

En sekvens är ungefär som en lista: det är ett oändligt objekt som kan ge dig sitt first element eller rest av dess element i konstant tid. Du kan också cons truct en ny sekvens från en befintlig sekvens och ett objekt att hålla i början.

Du kan testa om något är en sekvens med sekvensen seq? predikat:

(seq? nil)
;;=> false

(seq? 42)
;;=> false

(seq? :foo)
;;=> false

Som du redan vet är listor sekvenser:

(seq? ())
;;=> true

(seq? '(:foo :bar))
;;=> true

Allt du får genom att ringa seq eller rseq eller keys eller vals en icke-tom samling är också en sekvens:

(seq? (seq ()))
;;=> false

(seq? (seq '(:foo :bar)))
;;=> true

(seq? (seq []))
;;=> false

(seq? (seq [:foo :bar]))
;;=> true

(seq? (rseq []))
;;=> false

(seq? (rseq [:foo :bar]))
;;=> true

(seq? (seq {}))
;;=> false

(seq? (seq {:foo :bar :baz :qux}))
;;=> true

(seq? (keys {}))
;;=> false

(seq? (keys {:foo :bar :baz :qux}))
;;=> true

(seq? (vals {}))
;;=> false

(seq? (vals {:foo :bar :baz :qux}))
;;=> true

(seq? (seq #{}))
;;=> false

(seq? (seq #{:foo :bar}))
;;=> true

Kom ihåg att alla listor är sekvenser, men inte alla sekvenser är listor. Medan listor stöder peek och pop och count i konstant tid behöver i allmänhet en sekvens inte stödja någon av dessa funktioner. Om du försöker ringa peek eller pop på en sekvens som inte också stöder ClassCastException får du en ClassCastException :

(peek (seq [:foo :bar]))
;; java.lang.ClassCastException: clojure.lang.PersistentVector$ChunkedSeq cannot be cast to clojure.lang.IPersistentStack

(pop (seq [:foo :bar]))
;; java.lang.ClassCastException: clojure.lang.PersistentVector$ChunkedSeq cannot be cast to clojure.lang.IPersistentStack

(peek (seq #{:foo :bar}))
;; java.lang.ClassCastException: clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentStack

(pop (seq #{:foo :bar}))
;; java.lang.ClassCastException: clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentStack

(peek (seq {:foo :bar :baz :qux}))
;; java.lang.ClassCastException: clojure.lang.PersistentArrayMap$Seq cannot be cast to clojure.lang.IPersistentStack

(pop (seq {:foo :bar :baz :qux}))
;; java.lang.ClassCastException: clojure.lang.PersistentArrayMap$Seq cannot be cast to clojure.lang.IPersistentStack

Om du count på en sekvens som inte implementerar count i konstant tid får du inte ett fel; istället kommer Clojure att korsa hela sekvensen tills den når slutet och sedan returnerar antalet element som den korsade. Detta innebär att count för allmänna sekvenser är linjär, inte konstant, tid. Du kan testa om något stöder konstant count med det counted? predikat:

(counted? '(:foo :bar))
;;=> true

(counted? (seq '(:foo :bar)))
;;=> true

(counted? [:foo :bar])
;;=> true

(counted? (seq [:foo :bar]))
;;=> true

(counted? {:foo :bar :baz :qux})
;;=> true

(counted? (seq {:foo :bar :baz :qux}))
;;=> true

(counted? #{:foo :bar})
;;=> true

(counted? (seq #{:foo :bar}))
;;=> false

Som nämnts ovan kan du använda first att få det första elementet i en sekvens. Observera att first kommer att kalla seq på deras argument, så det kan användas på allt "seqable", inte bara faktiska sekvenser:

(first nil)
;;=> nil

(first '(:foo))
;;=> :foo

(first '(:foo :bar))
;;=> :foo

(first [:foo])
;;=> :foo

(first [:foo :bar])
;;=> :foo

(first {:foo :bar})
;;=> [:foo :bar]

(first #{:foo})
;;=> :foo

Som nämnts ovan kan du använda rest att få en sekvens som innehåller alla utom det första elementet i en befintlig sekvens. Liksom first , kallar det seq på sin argument. Men det kallar inte seq om sitt resultat! Detta innebär att om du ringer rest på en sekvens som innehåller färre än två objekt kommer du tillbaka () istället för nil :

(rest nil)
;;=> ()

(rest '(:foo))
;;=> ()

(rest '(:foo :bar))
;;=> (:bar)

(rest [:foo])
;;=> ()

(rest [:foo :bar])
;;=> (:bar)

(rest {:foo :bar})
;;=> ()

(rest #{:foo})
;;=> ()

Om du vill komma tillbaka nil när det inte finns fler element i en sekvens, kan du använda next istället för rest :

(next nil)
;;=> nil

(next '(:foo))
;;=> nil

(next [:foo])
;;=> nil

Du kan använda cons funktionen för att skapa en ny sekvens som kommer att returnera det första argumentet för det first och det andra argumentet för rest :

(cons :foo nil)
;;=> (:foo)

(cons :foo (cons :bar nil))
;;=> (:foo :bar)

Clojure tillhandahåller ett stort sekvensbibliotek med många funktioner för att hantera sekvenser. Det viktiga med detta bibliotek är att det fungerar med allt "sökbart", inte bara listor. Det är därför begreppet en sekvens är så användbart; det betyder att en enda funktion, som reduce , fungerar perfekt på alla samlingar:

(reduce + '(1 2 3))
;;=> 6

(reduce + [1 2 3])
;;=> 6

(reduce + #{1 2 3})
;;=> 6

Det andra skälet till att sekvenser är användbara är att eftersom de inte kräver någon speciell implementering av first och rest , tillåter de lata sekvenser vars element först realiseras när det är nödvändigt.

Med tanke på ett uttryck som skulle skapa en sekvens kan du linda in det uttrycket i det lazy-seq makroet för att få ett objekt som fungerar som en sekvens, men kommer bara faktiskt att utvärdera det uttrycket när det uppmanas att göra det med seq funktionen, vid vilken punkt det cachar resultatet av uttrycket och vidarebefordrar first och rest samtal till det cachade resultatet.

För ändliga sekvenser fungerar en lat sekvens vanligtvis på samma sätt som en ekvivalent ivrig sekvens:

(seq [:foo :bar])
;;=> (:foo :bar)

(lazy-seq [:foo :bar])
;;=> (:foo :bar)

Skillnaden blir emellertid uppenbar för oändliga sekvenser:

(defn eager-fibonacci [a b]
  (cons a (eager-fibonacci b (+' a b))))

(defn lazy-fibonacci [a b]
  (lazy-seq (cons a (lazy-fibonacci b (+' a b)))))

(take 10 (eager-fibonacci 0 1))
;; java.lang.StackOverflowError:

(take 10 (lazy-fibonacci 0 1))
;;=> (0 1 1 2 3 5 8 13 21 34)

vektorer

En vektor betecknas med fyrkantiga parenteser:

[]
;;=> []

[:foo]
;;=> [:foo]

[:foo :bar]
;;=> [:foo :bar]

[1 (+ 1 1) 3]
;;=> [1 2 3]

Förutom att använda den bokstavliga syntaxen kan du också använda vector att konstruera en vektor:

(vector)
;;=> []

(vector :foo)
;;=> [:foo]

(vector :foo :bar)
;;=> [:foo :bar]

(vector 1 (+ 1 1) 3)
;;=> [1 2 3]

Du kan testa om något är en vektor med vector? predikat:

(vector? [])
;;=> true

(vector? [:foo :bar])
;;=> true

(vector? nil)
;;=> false

(vector? 42)
;;=> false

(vector? :foo)
;;=> false

conj lägger till element i slutet av en vektor:

(conj [] :foo)
;;=> [:foo]

(conj (conj [] :foo) :bar)
;;=> [:foo :bar]

(conj [] :foo :bar)
;;=> [:foo :bar]

count ger antalet objekt i konstant tid:

(count [])
;;=> 0

(count (conj [] :foo))
;;=> 1

(count [:foo :bar])
;;=> 2

Du kan få det sista elementet i en vektor med peek :

(peek [])
;;=> nil

(peek [:foo])
;;=> :foo

(peek [:foo :bar])
;;=> :bar

Du kan få en ny vektor utan det sista elementet med pop :

(pop [:foo])
;;=> []

(pop [:foo :bar])
;;=> [:foo]

Observera att om du försöker poppa en tom vektor, får du en IllegalStateException :

(pop [])
;; java.lang.IllegalStateException: Can't pop empty vector

Till skillnad från listor indexeras vektorer. Du kan få ett element i en vektor efter index i "konstant" tid med hjälp av get :

(get [:foo :bar] 0)
;;=> :foo

(get [:foo :bar] 1)
;;=> :bar

(get [:foo :bar] -1)
;;=> nil

(get [:foo :bar] 2)
;;=> nil

Dessutom är vektorer själva funktioner som tar ett index och returnerar elementet vid det indexet:

([:foo :bar] 0)
;;=> :foo

([:foo :bar] 1)
;;=> :bar

Men om du kallar en vektor med ett ogiltigt index får du ett IndexOutOfBoundsException istället för nil :

([:foo :bar] -1)
;; java.lang.IndexOutOfBoundsException:

([:foo :bar] 2)
;; java.lang.IndexOutOfBoundsException:

Du kan få en ny vektor med ett annat värde vid ett visst index med hjälp av assoc :

(assoc [:foo :bar] 0 42)
;;=> [42 :bar]

(assoc [:foo :bar] 1 42)
;;=> [:foo 42]

Om du skickar ett index lika med count av vektorn kommer Clojure lägga elementet som om du hade använt conj . Men om du klarar ett index som är negativt eller högre än count får du ett IndexOutOfBoundsException :

(assoc [:foo :bar] 2 42)
;;=> [:foo :bar 42]

(assoc [:foo :bar] -1 42)
;; java.lang.IndexOutOfBoundsException:

(assoc [:foo :bar] 3 42)
;; java.lang.IndexOutOfBoundsException:

Du kan få en sekvens av objekten i en vektor med hjälp av seq :

(seq [])
;;=> nil

(seq [:foo])
;;=> (:foo)

(seq [:foo :bar])
;;=> (:foo :bar)

Eftersom vektorer är indexerade kan du också få en omvänd sekvens av en rseq objekt med hjälp av rseq :

(rseq [])
;;=> nil

(rseq [:foo])
;;=> (:foo)

(rseq [:foo :bar])
;;=> (:bar :foo)

Observera att även om alla listor är sekvenser och sekvenser visas på samma sätt som listor, är inte alla sekvenser listor!

'(:foo :bar)
;;=> (:foo :bar)

(seq [:foo :bar])
;;=> (:foo :bar)

(list? '(:foo :bar))
;;=> true

(list? (seq [:foo :bar]))
;;=> false

(list? (rseq [:foo :bar]))
;;=> false

Ställer

Liksom kartor är uppsättningar associerande och oordnade. Till skillnad från kartor, som innehåller mappningar från nycklar till värden, uppsätter i huvudsak kart från nycklar till sig själva.

En uppsättning betecknas med lockiga hängslen som föregås av en oktorporpe:

#{}
;;=> #{}

#{:foo}
;;=> #{:foo}

#{:foo :bar}
;;=> #{:bar :foo}

Liksom med kartor spelar ingen roll i vilken ordning elementen visas i en bokstavlig uppsättning:

(= #{:foo :bar} #{:bar :foo})
;;=> true

Du kan testa om något är en uppsättning med hjälp av set? predikat:

(set? #{})
;;=> true

(set? #{:foo})
;;=> true

(set? #{:foo :bar})
;;=> true

(set? nil)
;;=> false

(set? 42)
;;=> false

(set? :foo)
;;=> false

Du kan testa om en karta innehåller ett visst objekt i "konstant" tid med hjälp av contains? predikat:

(contains? #{} :foo)
;;=> false

(contains? #{:foo} :foo)
;;=> true

(contains? #{:foo} :bar)
;;=> false

(contains? #{} nil)
;;=> false

(contains? #{nil} nil)
;;=> true

Dessutom är uppsättningarna själva funktioner som tar ett element och returnerar det elementet om det finns i uppsättningen, eller nil om det inte är:

(#{} :foo)
;;=> nil

(#{:foo} :foo)
;;=> :foo

(#{:foo} :bar)
;;=> nil

(#{} nil)
;;=> nil

(#{nil} nil)
;;=> nil

Du kan använda conj att få en uppsättning som har alla element i en befintlig uppsättning, plus ett ytterligare objekt:

(conj #{} :foo)
;;=> #{:foo}

(conj (conj #{} :foo) :bar)
;;=> #{:bar :foo}

(conj #{:foo} :foo)
;;=> #{:foo}

Du kan använda disj att få en uppsättning som har alla element i en befintlig uppsättning minus ett objekt:

(disj #{} :foo)
;;=> #{}

(disj #{:foo} :foo)
;;=> #{}

(disj #{:foo} :bar)
;;=> #{:foo}

(disj #{:foo :bar} :foo)
;;=> #{:bar}

(disj #{:foo :bar} :bar)
;;=> #{:foo}

count ger antalet element i konstant tid:

(count #{})
;;=> 0

(count (conj #{} :foo))
;;=> 1

(count #{:foo :bar})
;;=> 2

Du kan få en sekvens av alla element i en uppsättning med seq :

(seq #{})
;;=> nil

(seq #{:foo})
;;=> (:foo)

(seq #{:foo :bar})
;;=> (:bar :foo)

Kartor

Till skillnad från listan, som är en sekventiell datastruktur, och vektorn, som är både sekventiell och associativ, är kartan uteslutande en associativ datastruktur. En karta består av en uppsättning kartläggningar från nycklar till värden. Alla nycklar är unika, så kartor stöder "konstant" uppslag från tid till nycklar till värden.

En karta betecknas med lockiga hängslen:

{}
;;=> {}

{:foo :bar}
;;=> {:foo :bar}

{:foo :bar :baz :qux}
;;=> {:foo :bar, :baz :qux}

Varje par av två element är ett nyckelvärdespar. Så till exempel har den första kartan ovan inga mappningar. Den andra har en kartläggning, från nyckeln :foo till värdet :bar . Den tredje har två mappningar, en från nyckeln :foo till värdet :bar , och en från nyckeln :baz till värdet :qux . Kartor är i sig ordenade, så ordningen i vilken kartläggningarna visas spelar ingen roll:

(= {:foo :bar :baz :qux}
   {:baz :qux :foo :bar})
;;=> true

Du kan testa om något är en karta med map? predikat:

(map? {})
;;=> true

(map? {:foo :bar})
;;=> true

(map? {:foo :bar :baz :qux})
;;=> true

(map? nil)
;;=> false

(map? 42)
;;=> false

(map? :foo)
;;=> false

Du kan testa om en karta innehåller en given nyckel i "konstant" tid med hjälp av contains? predikat:

(contains? {:foo :bar :baz :qux} 42)
;;=> false

(contains? {:foo :bar :baz :qux} :foo)
;;=> true

(contains? {:foo :bar :baz :qux} :bar)
;;=> false

(contains? {:foo :bar :baz :qux} :baz)
;;=> true

(contains? {:foo :bar :baz :qux} :qux)
;;=> false

(contains? {:foo nil} :foo)
;;=> true

(contains? {:foo nil} :bar)
;;=> false

Du kan få värdet associerat med en nyckel med hjälp av get :

(get {:foo :bar :baz :qux} 42)
;;=> nil

(get {:foo :bar :baz :qux} :foo)
;;=> :bar

(get {:foo :bar :baz :qux} :bar)
;;=> nil

(get {:foo :bar :baz :qux} :baz)
;;=> :qux

(get {:foo :bar :baz :qux} :qux)
;;=> nil

(get {:foo nil} :foo)
;;=> nil

(get {:foo nil} :bar)
;;=> nil

Dessutom är kartorna själva funktioner som tar en nyckel och returnerar värdet som är associerat med den tangenten:

({:foo :bar :baz :qux} 42)
;;=> nil

({:foo :bar :baz :qux} :foo)
;;=> :bar

({:foo :bar :baz :qux} :bar)
;;=> nil

({:foo :bar :baz :qux} :baz)
;;=> :qux

({:foo :bar :baz :qux} :qux)
;;=> nil

({:foo nil} :foo)
;;=> nil

({:foo nil} :bar)
;;=> nil

Du kan få en hel kartpost (nyckel och värde tillsammans) som en tvåelementvektor genom att find :

(find {:foo :bar :baz :qux} 42)
;;=> nil

(find {:foo :bar :baz :qux} :foo)
;;=> [:foo :bar]

(find {:foo :bar :baz :qux} :bar)
;;=> nil

(find {:foo :bar :baz :qux} :baz)
;;=> [:baz :qux]

(find {:foo :bar :baz :qux} :qux)
;;=> nil

(find {:foo nil} :foo)
;;=> [:foo nil]

(find {:foo nil} :bar)
;;=> nil

Du kan extrahera nyckeln eller värdet från en kartpost med hjälp av key respektive val :

(key (find {:foo :bar} :foo))
;;=> :foo

(val (find {:foo :bar} :foo))
;;=> :bar

Observera att även om alla Clojure-kartposter är vektorer, är inte alla vektorer kartposter. Om du försöker ringa key eller val på något som inte är en kartpost, får du en ClassCastException :

(key [:foo :bar])
;; java.lang.ClassCastException:

(val [:foo :bar])
;; java.lang.ClassCastException:

Du kan testa om något är en kartpost med hjälp av map-entry? predikat:

(map-entry? (find {:foo :bar} :foo))
;;=> true

(map-entry? [:foo :bar])
;;=> false

Du kan använda assoc att få en karta som har alla samma nyckelvärdespar som en befintlig karta, med en mappning tillagd eller ändrad:

(assoc {} :foo :bar)
;;=> {:foo :bar}

(assoc (assoc {} :foo :bar) :baz :qux)
;;=> {:foo :bar, :baz :qux}

(assoc {:baz :qux} :foo :bar)
;;=> {:baz :qux, :foo :bar}

(assoc {:foo :bar :baz :qux} :foo 42)
;;=> {:foo 42, :baz :qux}

(assoc {:foo :bar :baz :qux} :baz 42)
;;=> {:foo :bar, :baz 42}

Du kan använda dissoc att få en karta som har alla samma nyckelvärdespar som en befintlig karta, med eventuellt en kartläggning bort:

(dissoc {:foo :bar :baz :qux} 42)
;;=> {:foo :bar :baz :qux}

(dissoc {:foo :bar :baz :qux} :foo)
;;=> {:baz :qux}

(dissoc {:foo :bar :baz :qux} :bar)
;;=> {:foo :bar :baz :qux}

(dissoc {:foo :bar :baz :qux} :baz)
;;=> {:foo :bar}

(dissoc {:foo :bar :baz :qux} :qux)
;;=> {:foo :bar :baz :qux}

(dissoc {:foo nil} :foo)
;;=> {}

count ger antalet kartläggningar, i konstant tid:

(count {})
;;=> 0

(count (assoc {} :foo :bar))
;;=> 1

(count {:foo :bar :baz :qux})
;;=> 2

Du kan få en sekvens av alla poster på en karta med seq :

(seq {})
;;=> nil

(seq {:foo :bar})
;;=> ([:foo :bar])

(seq {:foo :bar :baz :qux})
;;=> ([:foo :bar] [:baz :qux])

Återigen är kartor oordnade, så beställningen av objekten i en sekvens som du får genom att ringa seq på en karta är odefinierad.

Du kan få en sekvens av bara tangenterna eller bara värdena på en karta med hjälp av keys respektive vals :

(keys {})
;;=> nil

(keys {:foo :bar})
;;=> (:foo)

(keys {:foo :bar :baz :qux})
;;=> (:foo :baz)

(vals {})
;;=> nil

(vals {:foo :bar})
;;=> (:bar)

(vals {:foo :bar :baz :qux})
;;=> (:bar :qux)

Clojure 1.9 lägger till en bokstavlig syntax för att mer kortfattat representerar en karta där tangenterna delar samma namnutrymme. Observera att kartan i båda fallen är identisk (kartan "känner inte" standardnamnområdet), detta är bara en syntaktisk bekvämlighet.

;; typical map syntax
(def p {:person/first"Darth" :person/last "Vader" :person/email "[email protected]"})

;; namespace map literal syntax
(def p #:person{:first "Darth" :last "Vader" :email "[email protected]"})


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow