如何使用"与" Elixir中的关键字及其用途是什么?

时间:2015-12-10 19:36:05

标签: elixir

在elixir 1.2中,他们已经将关键字"与"包括在一起,但它并不完全清楚我的目的是什么。

我将如何以及在何种情况下使用它?

3 个答案:

答案 0 :(得分:67)

在1.2之前的Elixir版本中,当在管道中使用函数时,您将不得不使用monad库或嵌套case语句(可以使用私有函数重构,但最终仍然是冗长的)。 with/1允许以不同的方式解决此问题。

以下是original proposal

的示例
case File.read(path) do
  {:ok, binary} ->
    case :beam_lib.chunks(binary, :abstract_code) do
      {:ok, data} ->
        {:ok, wrap(data)}
      error ->
        error
    end
  error ->
    error
end

以下是使用函数重构的相同内容:

path
|> File.read()
|> read_chunks()
|> wrap()

defp read_chunks({:ok, binary}) do
  {:ok, :beam_lib.chunks(binary, :abstract_code)}
end
defp read_chunks(error), do: error

defp wrap({:ok, data}) do
  {:ok, wrap(data)}
end
defp wrap(error), do: error

使用with的相同代码:

with {:ok, binary} <- File.read(path),
     {:ok, data} <- :beam_lib.chunks(binary, :abstract_code),
     do: {:ok, wrap(data)}

这是有效的,因为如果值与左侧的模式匹配,with将仅保持链接。如果不是,则中止链并返回第一个不匹配的结果。例如,如果该文件不存在,那么File.read(path)将返回{:error, :enoent} - 这与{:ok, binary}不符,因此with/1调用将返回{:error, :enoent}.

值得注意的是,with可以与任何模式一起使用,而不仅仅是{:ok, foo}{:error, reason}(尽管这是一个非常常见的用例)。

答案 1 :(得分:16)

你也可以链接“裸表达式”,正如文档所说:

with {:ok, binary} <- File.read(path),
     header = parse_header(binary),
     {:ok, data} <- :beam_lib.chunks(header, :abstract_code),
     do: {:ok, wrap(data)}

变量header仅在with语句中可用。有关详情,请访问https://gist.github.com/josevalim/8130b19eb62706e1ab37

答案 2 :(得分:3)

有一点需要注意,您可以在when声明中使用with后卫。 E.g,

defmodule Test do
  def test(res) do
    with {:ok, decode_res} when is_map(decode_res) <- res
    do
      IO.inspect "ok"
    else
      decode_res when is_map(decode_res) -> IO.inspect decode_res
      _ ->
        IO.inspect "error"
    end
  end
end
Test.test({:ok , nil})
Test.test({:ok , 12})
Test.test({:ok , %{}})