當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Elixir Kernel.SpecialForms.with用法及代碼示例


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 File.exists?/1 的結果類型來構建錯誤消息。在這種情況下,最好將 with 子句更改為已經返回所需的格式,如下所示:

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-lang.org大神的英文原創作品 Kernel.SpecialForms.with(args)。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。