- Mastering Elixir
- André Albuquerque Daniel Caixinha
- 527字
- 2021-08-05 10:42:49
with
This control-flow construct, introduced in Elixir 1.2, accepts one or more expressions, a do block, and optionally an else block. It allows you to use pattern matching on the return value of each expression, running the do block if every pattern matches. If one of the patterns doesn't match, two things may happen: If provided, the else block will be executed; otherwise, it will return the value that didn't match the expression. In practice, with allows you to replace a chain of nested instances of case or a group of multi-clause functions.
To demonstrate the usefulness of with, let's see an example:
iex> options = [x: [y: [z: "the value we're after!"]]]
[x: [y: [z: "the value we're after!"]]]
iex> case Keyword.fetch(options, :x) do
...> {:ok, value} -> case Keyword.fetch(value, :y) do
...> {:ok, inner_value} -> case Keyword.fetch(inner_value, :z) do
...> {:ok, inner_inner_value} -> inner_inner_value
...> _ -> "non-existing key"
...> end
...> _ -> "non-existing key"
...> end
...> _ -> "non-existing key"
...> end
"the value we're after!"
We're using the Keyword.fetch/2 function to get the value of a key from a keyword list. This function returns {:ok, value} when the key exists, and :error otherwise. We want to retrieve the value that's nested on three keyword lists. However, let's say that if we try to fetch a key that doesn't exist on the keyword list, we have to return "non-existing key". Let's achieve the same behavior using with, operating on the same options list as the preceding example:
iex> with {:ok, value} <- Keyword.fetch(options, :x),
...> {:ok, inner_value} <- Keyword.fetch(value, :y),
...> {:ok, inner_inner_value} <- Keyword.fetch(inner_value, :z),
...> do: inner_inner_value
"the value we're after!"
Note that, since our expression is really small, we're using the shorthand do: syntax (but we can also use a regular do ... end block). As you can see, we're getting the same result back. Let's try to fetch a key that doesn't exist:
iex> with {:ok, value} <- Keyword.fetch(options, :missing_key),
...> {:ok, inner_value} <- Keyword.fetch(value, :y),
...> {:ok, inner_inner_value} <- Keyword.fetch(inner_value, :z),
...> do: inner_inner_value
:error
Since we didn't provide an else block, we're getting back the value that didn't match, which is the return value of Keyword.fetch/2 when a key doesn't exist in the keyword list provided. Let's do the same, but by providing an else block:
iex> with {:ok, value} <- Keyword.fetch(options, :missing_key),
...> {:ok, inner_value} <- Keyword.fetch(value, :y),
...> {:ok, inner_inner_value} <- Keyword.fetch(inner_value, :z) do
...> inner_inner_value
...> else
...> :error -> "non-existing key"
...> _ -> "some other error"
...> end
"non-existing key"
Since we're now providing an else block, we can now handle error cases accordingly. As you can see, else takes a list of patterns to match on. As you do with case, you can use _ as a default clause, which would run when the patterns above (if any) didn't match.
As you can see, with is a very helpful construct, which allows us to create very expressive code that is concise and easy to read. Moreover, you can control how to handle each error separately, using pattern matching inside the else block.
- Java多線程編程實戰指南:設計模式篇(第2版)
- 動手玩轉Scratch3.0編程:人工智能科創教育指南
- The Data Visualization Workshop
- PHP+MySQL網站開發項目式教程
- QGIS:Becoming a GIS Power User
- Kotlin從基礎到實戰
- .NET Standard 2.0 Cookbook
- Learning VMware vSphere
- C陷阱與缺陷
- Django Design Patterns and Best Practices
- SSH框架企業級應用實戰
- 3ds Max 2018從入門到精通
- 美麗洞察力:從化妝品行業看顧客需求洞察
- C#編程魔法書
- Java無難事:詳解Java編程核心思想與技術