Ответ 1
Вот несколько способов.
user> (update-in person [:name] assoc :first-name "Bob" :last-name "Doe")
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
user> (update-in person [:name] merge {:first-name "Bob" :last-name "Doe"})
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
user> (update-in person [:name] into {:first-name "Bob" :last-name "Doe"})
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
user> (-> person
(assoc-in [:name :first-name] "Bob")
(assoc-in [:name :last-name] "Doe"))
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
Изменить
update-in
Рекурсивный assoc
на вашей карте. В этом случае это примерно эквивалентно:
user> (assoc person :name
(assoc (:name person)
:first-name "Bob"
:last-name "Doe"))
Повторение ключей становится все более утомительным, когда вы углубляетесь в ряд вложенных карт. Рекурсия update-in
позволяет избежать повторения клавиш (например, :name
) снова и снова; промежуточные результаты хранятся в стеке между рекурсивными вызовами. Взгляните на источник update-in, чтобы узнать, как это делается.
user> (def foo {:bar {:baz {:quux 123}}})
#'user/foo
user> (assoc foo :bar
(assoc (:bar foo) :baz
(assoc (:baz (:bar foo)) :quux
(inc (:quux (:baz (:bar foo)))))))
{:bar {:baz {:quux 124}}}
user> (update-in foo [:bar :baz :quux] inc)
{:bar {:baz {:quux 124}}}
assoc
является динамическим (как update-in
, assoc-in
и большинство других функций Clojure, которые работают с структурами данных Clojure). Если assoc
на карте, оно возвращает карту. Если вы assoc
на вектор, он возвращает вектор. Посмотрите источник assoc и загляните в RT.java
в источнике Clojure для получения подробной информации.