UP | HOME

Elixir with 笔记

Table of Contents

1 TLDR

简单的说

defp serve(socket) do
  msg =
    case read_line(socket) do
      {:ok, data} ->
        case KVServer.Command.parse(data) do
          {:ok, command} ->
            KVServer.Command.run(command)
          {:error, _} = err ->
            err
        end
      {:error, _} = err ->
        err
    end

  write_line(socket, msg)
  serve(socket)
end

像这种代码使用 with 可以重构成下面的形式,来避免 case 嵌套

defp serve(socket) do
  msg =
    with {:ok, data} <- read_line(socket),
         {:ok, command} <- KVServer.Command.parse(data),
         do: KVServer.Command.run(command)

  write_line(socket, msg)
  serve(socket)
end

代码来自 https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#with

with 接收 <- 右边的值,进行模式匹配,如果匹配成功,则继续下一个表达式,直到所有的匹配成功执行 do 代码块,否则中止返回不匹配的值

2 syntax

doc: https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1

iex> opts = %{width: 10, height: 15}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...>      {:ok, height} <- Map.fetch(opts, :height),
...>      do: {:ok, width * height}
{:ok, 150}

所有区配都成功 返回 {:ok, 150}

iex> opts = %{width: 10}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...>      {:ok, height} <- Map.fetch(opts, :height),
...>      do: {:ok, width * height}
:error

{:ok, height} <- Map.fetch(opts, :height) 失败, 返回 Map.fetch(opts, :height) 的返回值 :error

支持 when

iex> users = %{"melany" => "guest", "bob" => :admin}
iex> with {:ok, role} when not is_binary(role) <- Map.fetch(users, "bob"),
...>      do: {:ok, to_string(role)}
{:ok, "admin"}

with 里的变量只在 with 下生效

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}
{:ok, 300}
iex> width
nil

width 最后还是 nil

可以加 else 处理匹配中止的情况

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}
...> end
{:error, :wrong_data}

如果 else 不匹配,抛出 WithClauseError 异常

3 links

Author: lidashuang

Created: 2018-05-20 Sun 03:57

Emacs 25.3.3 (Org mode 8.2.10)