Elixir列表叶子节点更新咨询:put_in、update_in及MapSet用法
完全正确!当嵌套结构的叶子是列表时,put_in确实会直接覆盖整个列表,这时候**update_in就是你需要的工具**——它的核心作用就是对嵌套结构里的某个值执行「转换更新」,而非直接替换。下面分两种场景给你具体演示:
场景1:叶子节点是列表
假设我们有这样的嵌套Map:
data = %{user: %{posts: ["first post", "second post"]}}
如果误用put_in来添加元素,结果会直接替换掉整个列表:
put_in(data, [:user, :posts], 2) # 返回:%{user: %{posts: 2}} → 这显然不是我们想要的
用update_in的话,我们可以传入一个函数,接收原来的列表,返回添加元素后的新列表:
# 追加元素到列表末尾 update_in(data, [:user, :posts], fn list -> list ++ [2] end) # 返回:%{user: %{posts: ["first post", "second post", 2]}} # 如果想把元素加到列表开头,可以用 cons 操作符 update_in(data, [:user, :posts], fn list -> [2 | list] end) # 返回:%{user: %{posts: [2, "first post", "second post"]}}
update_in会自动帮我们把函数返回的新列表,放回原嵌套结构对应的位置。
场景2:叶子节点是MapSet
MapSet是Elixir里的不可变集合类型,更新它需要用到MapSet模块的函数(比如MapSet.put),同样用update_in来完成嵌套结构的更新:
先定义初始数据:
data = %{user: %{tags: MapSet.new(["elixir", "functional"])}}
然后用update_in结合MapSet.put添加新元素:
update_in(data, [:user, :tags], fn set -> MapSet.put(set, "web") end) # 返回:%{user: %{tags: #MapSet<["elixir", "functional", "web"]>}}
这里要注意,所有Elixir的不可变数据结构,更新时都会返回新的实例,update_in的作用就是把这个新实例重新嵌入到原来的嵌套Map中。
如果需要更复杂的更新(比如同时获取旧值和设置新值),还可以用get_and_update_in,但大部分简单的添加场景,update_in就足够好用了。
内容的提问来源于stack exchange,提问作者Thomas Browne
相关产品推荐
相关产品推荐

