Elixir语言中 Kernel.SpecialForms.with
相关用法介绍如下。
用法:
with(args)
(宏)
用于组合匹配子句。
让我们从一个例子开始:
iex> opts = %{width: 10, height: 15}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...> {:ok, height} <- Map.fetch(opts, :height) do
...> {:ok, width * height}
...> end
{:ok, 150}
如果所有子句都匹配,则执行 do
块,并返回其结果。否则,链中止并返回不匹配的值:
iex> opts = %{width: 10}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...> {:ok, height} <- Map.fetch(opts, :height) do
...> {:ok, width * height}
...> end
:error
守卫也可以在模式中使用:
iex> users = %{"melany" => "guest", "bob" => :admin}
iex> with {:ok, role} when not is_binary(role) <- Map.fetch(users, "bob") do
...> {:ok, to_string(role)}
...> end
{:ok, "admin"}
与
一样,绑定在 for/1
内的变量不会泄漏。没有with/1
<-
的表达式也可以用在子句中。例如,您可以使用 =
运算符执行常规匹配:
iex> width = nil
iex> opts = %{width: 10, height: 15}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...> double_width = width * 2,
...> {:ok, height} <- Map.fetch(opts, :height) do
...> {:ok, double_width * height}
...> end
{:ok, 300}
iex> width
nil
子句中任何表达式的行为都与在 with
之外编写的行为相同。例如,=
将引发
而不是返回不匹配的值:MatchError
with :foo = :bar, do: :ok
** (MatchError) no match of right hand side value: :bar
与 Elixir 中的任何其他函数或宏调用一样,也可以在 do
- end
块之前的参数周围使用显式括号:
iex> opts = %{width: 10, height: 15}
iex> with(
...> {:ok, width} <- Map.fetch(opts, :width),
...> {:ok, height} <- Map.fetch(opts, :height)
...> ) do
...> {:ok, width * height}
...> end
{:ok, 150}
parens 和 no parens 之间的选择是一个偏好问题。
其他条款
在匹配失败的情况下,可以给出 else
选项来修改从 with
返回的内容:
iex> opts = %{width: 10}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...> {:ok, height} <- Map.fetch(opts, :height) do
...> {:ok, width * height}
...> else
...> :error ->
...> {:error, :wrong_data}
...>
...> _other_error ->
...> :unexpected_error
...> end
{:error, :wrong_data}
else
块的工作方式类似于case
子句:它可以有多个子句,并且将使用第一个匹配项。 with
内绑定的变量(例如本例中的 width
)在 else
块中不可用。
如果使用 else
块并且没有匹配的子句,则会引发
异常。WithClauseError
谨防!
请记住,with
的潜在缺点之一是所有失败子句都被扁平化为单个 else
块。例如,使用以下代码检查给定路径是否指向 Elixir 文件,并且在创建备份副本之前它是否存在:
with ".ex" <- Path.extname(path),
true <- File.exists?(path) do
backup_path = path <> ".backup"
File.cp!(path, backup_path)
{:ok, backup_path}
else
binary when is_binary(binary) ->
{:error, :invalid_extension}
false ->
{:error, :missing_file}
end
请注意,我们必须如何重构
和 Path.extname/1
的结果类型来构建错误消息。在这种情况下,最好将 with 子句更改为已经返回所需的格式,如下所示:File.exists?/1
with :ok <- validate_extension(path),
:ok <- validate_exists(path) do
backup_path = path <> ".backup"
File.cp!(path, backup_path)
{:ok, backup_path}
end
defp validate_extname(path) do
if Path.extname(path) == ".ex", do: :ok, else: {:error, :invalid_extension}
end
defp validate_exists(path) do
if File.exists?(path), do: :ok, else: {:error, :missing_file}
end
请注意,一旦我们确保 with
中的每个子句都返回规范化格式,上面的代码是如何组织得更好和更清晰的。
相关用法
- Elixir Kernel.SpecialForms.case用法及代码示例
- Elixir Kernel.SpecialForms.%{}用法及代码示例
- Elixir Kernel.SpecialForms.for用法及代码示例
- Elixir Kernel.SpecialForms.quote用法及代码示例
- Elixir Kernel.SpecialForms.require用法及代码示例
- Elixir Kernel.SpecialForms.&expr用法及代码示例
- Elixir Kernel.SpecialForms.<<args>>用法及代码示例
- Elixir Kernel.SpecialForms.{args}用法及代码示例
- Elixir Kernel.SpecialForms.unquote_splicing用法及代码示例
- Elixir Kernel.SpecialForms.receive用法及代码示例
- Elixir Kernel.SpecialForms.%struct{}用法及代码示例
- Elixir Kernel.SpecialForms.import用法及代码示例
- Elixir Kernel.SpecialForms.left . right用法及代码示例
- Elixir Kernel.SpecialForms.alias用法及代码示例
- Elixir Kernel.SpecialForms.try用法及代码示例
- Elixir Kernel.SpecialForms.fn用法及代码示例
- Elixir Kernel.SpecialForms.cond用法及代码示例
- Elixir Kernel.SpecialForms.__aliases__用法及代码示例
- Elixir Kernel.SpecialForms.left :: right用法及代码示例
- Elixir Kernel.SpecialForms.unquote用法及代码示例
- Elixir Kernel.SpecialForms.__block__用法及代码示例
- Elixir Kernel.SpecialForms.^var用法及代码示例
- Elixir Kernel.round用法及代码示例
- Elixir Kernel.left / right用法及代码示例
- Elixir Kernel.put_in用法及代码示例
注:本文由纯净天空筛选整理自elixir-lang.org大神的英文原创作品 Kernel.SpecialForms.with(args)。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。