Structs

Structs are key-value maps with keyword keys. {...} is immutable; @{...} is mutable.

Literals

{:name "Alice" :age 30}    # immutable struct
@{:name "Alice" :age 30}   # mutable @struct

Access

(def user {:name "Alice" :age 30 :role :admin})

(get user :name)           # => "Alice"
(get user :missing :nope)  # => :nope (default value)
(has? user :age)           # => true
(length user)              # => 3

# callable struct syntax
(user :name)               # => "Alice"

# accessor syntax: obj:field is sugar for (get obj :field)
user:name                  # => "Alice"
user:role                  # => :admin

Immutable updates

Operations on immutable structs return new structs. The original is unchanged. Both put and del return the resulting struct (new for immutable, same reference for mutable).

(def user {:name "Alice" :age 30})

(put user :email "a@b.com")   # => {:name "Alice" :age 30 :email "a@b.com"}
(del user :age)                # => {:name "Alice"}
(update user :age inc)         # => {:name "Alice" :age 31}
(merge user {:age 31 :role :admin})
# => {:name "Alice" :age 31 :role :admin}

Introspection

(keys {:a 1 :b 2})         # => (:a :b)   (sorted order)
(values {:a 1 :b 2})       # => (1 2)     (matching key order)
(pairs {:a 1 :b 2})        # => ([a 1] [b 2])  (list of [key value] arrays)
(from-pairs [[:a 1] [:b 2]])  # => {:a 1 :b 2}

pairs returns a list of [key value] arrays in sorted key order. Combined with from-pairs, structs can be round-tripped through list operations:

(def s {:x 1 :y 2 :z 3})
(from-pairs (filter (fn [p] (> (get p 1) 1)) (pairs s)))
# => {:y 2 :z 3}

Nested access and update

(def config {:db {:host "localhost" :port 5432}})

(get-in config [:db :host])          # => "localhost"
(put-in config [:db :port] 3306)     # => {:db {:host "localhost" :port 3306}}
(update-in config [:db :port] inc)   # => {:db {:host "localhost" :port 5433}}

Mutable @structs

put and del on @struct mutate in place and return the same struct.

(def tbl @{:count 0})
(put tbl :count 1)         # mutates tbl, returns tbl
(put tbl :name "Bob")      # adds key, returns tbl
tbl:count                  # => 1
tbl:name                   # => "Bob"
(del tbl :name)            # removes key, returns tbl

Destructuring

(def {:name n :age a} {:name "Alice" :age 30})
n                          # => "Alice"
a                          # => 30

# & collects remaining keys
(def {:a va & rest} {:a 1 :b 2 :c 3})
rest                       # => {:b 2 :c 3}

See also