Elixirのネストしたデータ構造を操作するビルトイン関数にput_in
, update_in
があります。
put_in
put_in(path, value)でネストしたデータ構造のプロパティを変更して新しい構造を返します。
注意する点は、Elixirの変数はimmutableなので、もとの変数のプロパティは変更されません。
iex> foo = %{person: %{name: "foo", age: 21}, place: "Shibuya"}
iex> put_in(foo.person.age, 30)
%{person: %{age: 30, name: "foo"}, place: "Shibuya"}
iex> foo
%{person: %{age: 21, name: "foo"}, place: "Shibuya"}
update_in
update_in
はput_in
の第二引数として関数を受け取ります。
iex> foo = %{person: %{name: "foo", age: 21}, place: "Shibuya"}
iex> update_in(foo.person.age, fn age -> age + 1 end)
%{person: %{age: 22, name: "foo"}, place: "Shibuya"}
マップだけでなく、構造体にも適用することができます。
defmodule User do
defstruct name: nil, text: nil, place: nil
end
defmodule Message do
defstruct user: nil, text: nil, place: nil
end
message = %Message{user: %User{name: "foo", age: 21}, text "Yay!", place: "Shibuya"}
update_in(message.user.age, &(&1 + 1))
// => %Message{place: "Shibuya", text: "Yay!", user: %User{age: 22, name: "foo"}}