当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Elixir Kernel.get_and_update_in用法及代码示例


Elixir语言中 Kernel.get_and_update_in 相关用法介绍如下。

用法一

get_and_update_in(path, fun)
(宏)

通过给定的 path 获取值并更新嵌套数据结构。

这类似于 get_and_update_in/3 ,除了路径是通过宏提取而不是传递列表。例如:

get_and_update_in(opts[:foo][:bar], &{&1, &1 + 1})

相当于:

get_and_update_in(opts, [:foo, :bar], &{&1, &1 + 1})

这也适用于嵌套结构和 struct.path.to.value 指定路径的方式:

get_and_update_in(struct.foo.bar, &{&1, &1 + 1})

请注意,为了使此宏工作,完整路径必须始终对此宏可见。请参阅下面的"Paths" 部分。

例子

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users["john"].age, &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}

路径

路径可以以变量、本地或远程调用开始,并且必须后跟一个或多个:

  • foo[bar] - 访问 foo 中的 key bar ;如果 foo 为 nil,则返回 nil

  • foo.bar - 访问映射/结构字段;如果该字段不存在,则会引发错误

以下是一些有效路径:

users["john"][:age]
users["john"].age
User.all()["john"].age
all_users()["john"].age

以下是一些无效的:

# Does a remote call after the initial value
users["john"].do_something(arg1, arg2)

# Does not access any key or field
users

用法二

get_and_update_in(data, keys, fun)
@spec get_and_update_in(
  structure,
  keys,
  (term() | nil -> {current_value, new_value} | :pop)
) :: {current_value, new_structure :: structure}
when structure: Access.t(),
     keys: [any(), ...],
     current_value: Access.value(),
     new_value: Access.value()

获取一个值并更新一个嵌套结构。

data 是一个嵌套结构(即实现 Access 行为的映射、关键字列表或结构)。

fun 参数接收 key 的值(或 nil,如果 key 不存在)并且必须返回以下值之一:

  • 一个二元素元组 {current_value, new_value} 。在这种情况下,current_value 是检索到的值,可以在返回之前对其进行操作。 new_value 是要存储在 key 下的新值。

  • :pop ,这意味着 key 下的当前值应从结构中删除并返回。

此函数使用 Access 模块根据给定的 keys 遍历结构,除非 key 是一个函数,这将在后面的部分中详细介绍。

例子

当需要检索当前值(或根据当前值计算的值)并同时更新它时,此函数很有用。例如,它可以用于读取用户的当前年龄,同时将其增加一倍:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["john", :age], &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}

请注意,赋予匿名函数的当前值可能是 nil 。如果任何中间值为零,它将引发:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["jane", :age], &{&1, &1 + 1})
** (ArgumentError) could not put/update key :age on a nil value

作为键的函数

如果键是一个函数,该函数将被调用并传递三个参数:

  • 操作(:get_and_update)
  • 要访问的数据
  • 接下来要调用的函数

这意味着可以扩展 get_and_update_in/3 以提供自定义查找。缺点是函数不能作为键存储在访问的数据结构中。

当其中一个键是函数时,调用该函数。在下面的示例中,我们使用一个函数来获取和递增列表中的所有年龄:

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get_and_update, data, next ->
...>   data |> Enum.map(next) |> Enum.unzip()
...> end
iex> get_and_update_in(users, [all, :age], &{&1, &1 + 1})
{[27, 23], [%{name: "john", age: 28}, %{name: "meg", age: 24}]}

如果调用函数之前的前一个值是 nil ,则函数 will 接收 nil 作为值并且必须相应地处理它(无论是失败还是提供合理的默认值)。

Access 模块附带许多便利访问器函数,例如上面定义的all 匿名函数。请参阅 Access.all/0 Access.key/2 和其他示例。

相关用法


注:本文由纯净天空筛选整理自elixir-lang.org大神的英文原创作品 Kernel.get_and_update_in(path, fun)。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。