查看源代码 case、cond 和 if

在本章中,我们将学习 casecondif 控制流结构。

case

case 允许我们对一个值进行多种模式匹配,直到找到匹配的模式。

iex> case {1, 2, 3} do
...>   {4, 5, 6} ->
...>     "This clause won't match"
...>   {1, x, 3} ->
...>     "This clause will match and bind x to 2 in this clause"
...>   _ ->
...>     "This clause would match any value"
...> end
"This clause will match and bind x to 2 in this clause"

如果要对已有的变量进行模式匹配,需要使用 ^ 运算符。

iex> x = 1
1
iex> case 10 do
...>   ^x -> "Won't match"
...>   _ -> "Will match"
...> end
"Will match"

子句还允许通过守卫指定额外的条件。

iex> case {1, 2, 3} do
...>   {1, x, 3} when x > 0 ->
...>     "Will match"
...>   _ ->
...>     "Would match, if guard condition were not satisfied"
...> end
"Will match"

上面的第一个子句只有当 x 为正数时才会匹配。

请记住,守卫中的错误不会泄露,只会导致守卫失败。

iex> hd(1)
** (ArgumentError) argument error
iex> case 1 do
...>   x when hd(x) -> "Won't match"
...>   x -> "Got #{x}"
...> end
"Got 1"

如果所有子句都不匹配,则会引发错误。

iex> case :ok do
...>   :error -> "Won't match"
...> end
** (CaseClauseError) no case clause matching: :ok

Kernel 模块的文档在侧边栏列出了所有可用的守卫。您也可以查阅完整的 模式和守卫 参考以获取深入的文档。

cond

当您需要针对不同的值进行匹配时,case 很有用。但是,在许多情况下,我们希望检查不同的条件并找到第一个不评估为 nilfalse 的条件。在这种情况下,可以使用 cond

iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...> end
"But this will"

这等同于许多命令式语言中的 else if 子句 - 尽管在 Elixir 中使用频率较低。

如果所有条件都返回 nilfalse,则会引发错误 (CondClauseError)。出于这个原因,您可能需要添加一个最终条件,等于 true,它将始终匹配。

iex> cond do
...>   2 + 2 == 5 ->
...>     "This is never true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   true ->
...>     "This is always true (equivalent to else)"
...> end
"This is always true (equivalent to else)"

最后,请注意 cond 将任何除 nilfalse 之外的值都视为真值。

iex> cond do
...>   hd([1, 2, 3]) ->
...>     "1 is considered as true"
...> end
"1 is considered as true"

if/unless

除了 casecond 之外,Elixir 还提供 if/2unless/2,当您只需要检查一个条件时,它们很有用。

iex> if true do
...>   "This works!"
...> end
"This works!"
iex> unless true do
...>   "This will never be seen"
...> end
nil

如果给定给 if/2 的条件返回 falsenil,则在 do-end 之间给定的主体不会执行,而是返回 nilunless/2 则相反。

它们还支持 else 代码块。

iex> if nil do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

这也是谈论 Elixir 中变量作用域的好机会。如果在 ifcase 和类似结构中声明或更改任何变量,则声明和更改将只能在该结构中可见。例如

iex> x = 1
1
iex> if true do
...>   x = x + 1
...> end
2
iex> x
1

在这种情况下,如果要更改值,必须从 if 中返回值。

iex> x = 1
1
iex> x = if true do
...>   x + 1
...> else
...>   x
...> end
2

ifunless 是宏。

关于 if/2unless/2 的一个有趣之处是,它们在语言中被实现为宏:它们不是像在许多语言中那样是特殊的语言结构。您可以查看文档及其源代码以获取更多信息。

我们已经完成了对 Elixir 中最基本控制流结构的介绍。现在让我们学习代码和数据在匿名函数中相遇的地方。