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)。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。