文档章节

elixir官方入门教程 case,cond和if

ljzn
 ljzn
发布于 2016/08/02 20:36
字数 1489
阅读 66
收藏 0

#case,cond和if

1. `case`
2. 卫语句中的表达式
3. `cond`
4. `if`和`unless`
5. `do/end`块

本章,我们将学习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是正数时才能匹配。

#卫语句中的表达式

Elixir默认在卫语句中可以使用以下表达式:

- 比较运算符(==,!=,===,!==,>,>=,<,<=)
- 布尔运算符(and,or,not)
- 数学运算符(+,-,*,/)
- 一元运算符(+,-)
- 二进制连接符`<>`
- 当右边是一个范围或列表时,使用`in`操作符
- 下列的所有类型检查函数:
is_atom/1
is_binary/1
is_bitstring/1
is_boolean/1
is_float/1
is_function/1
is_function/2
is_integer/1
is_list/1
is_map/1
is_nil/1
is_number/1
is_pid/1
is_port/1
is_reference/1
is_tuple/1
- 加上这些函数
abs(number)
binary_part(binary, start, length)
bit_size(bitstring)
byte_size(bitstring)
div(integer, integer)
elem(tuple, n)
hd(list)
length(list)
map_size(map)
node()
node(pid | ref | port)
rem(integer, integer)
round(number)
self()
tl(list)
trunc(number)
tuple_size(tuple)

此外,用户可以定义自己的卫语句。例如,Bitwise模块使用函数和操作符来定义卫语句:bnot, ~~~, band, &&&, bor, |||, bxor, ^^^, bsl, <<<, bsr, >>>

注意,尽管例如andornot的布尔操作符允许在卫语句中使用,但更常用的短路操作符&&||!却不被允许。

记住,卫语句中的错误不会泄露,只是简单地让卫语句失败:

iex> hd(1)
** (ArgumentError) argument error
    :erlang.hd(1)
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

注意匿名函数也可以拥有多个卫语句:

iex> f = fn
...>   x, y when x > 0 -> x + y
...>   x, y -> x * y
...> end
#Function<12.71889879/2 in :erl_eval.expr/5>
iex> f.(1, 3)
4
iex> f.(-1, 3)
-3

匿名函数的分语句中参数的数量应当相同,否则会抛出错误。

iex> f2 = fn
...>   x, y when x > 0 -> x + y
...>   x, y, z -> x * y + z
...> end
** (CompileError) iex:1: cannot mix clauses with different arities in function definition

#cond

当你想要匹配不同的值时可以用case。然而,我们有时想要检查不同的情形并找出其中第一个结果为真的。这时,我们可以使用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从句是一样的(虽然在这里不经常用到)。

如果没有一种情况返回为真,则抛出一个错误(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"

#ifunless

除了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的情况返回值是falsenildo/end中的代码就不会执行并只返回nilunless/2正相反。

它们也支持else块:

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

注意:在这里if/2unless/2是被当作宏来执行的;而非其它许多语言中一样作为特殊的结构体。你可以在Kernel模块文档中查看说明文档和if/2的源代码。Kernel模块中定义了诸如+/2之类的操作符和'if_function/2`之类的函数,它们全都默认自动导入并在你的代码中可用。

#do/end

目前,我们已经学习了四种控制结构:casecondifunless,它们都包含了do/end块。所以我们也能够以如下方式写if语句:

iex> if true, do: 1 + 2
3

注意在truedo:之间有一个逗号,这是因为Elixir中参数之间要以逗号隔开。我们称这种格式为关键字列表。我们也可以用关键字来传递else

iex> if false, do: :this, else: :that
:that

do/end块形式是在关键字形式的语法上经过化简所得的。这就是为什么do/end块形式不要求参数与块之间用逗号隔开。它消除了在书写块代码时的冗余信息。下列两种语法作用是相同的:

iex> if true do
...>   a = 1 + 2
...>   a + 10
...> end
13
iex> if true, do: (
...>   a = 1 + 2
...>   a + 10
...> )
13

需要记住的是在使用do/end块时,它们总是和最外层的函数调用捆绑在一起。例如:

iex> is_number if true do
...>  1 + 2
...> end
** (CompileError) undefined function: is_number/2

会被解释成:

iex> is_number(if true) do
...>  1 + 2
...> end
** (CompileError) undefined function: is_number/2

产生错误的原因是Elixir试图调用is_number/1函数,却得到了两个参数(if true表达式也会产生错误,因为if需要它的第二个参数,也就是do/end块)。添加明确的括号能够消除歧义:

iex> is_number(if true do
...>  1 + 2
...> end)
true

关键字列表在语言中扮演着重要的角色,在许多函数与宏中都很常见。在之后的章节中我们会继续他;探索它。现在,让我们谈谈“二进制,字符串和字符列表”。

© 著作权归作者所有

共有 人打赏支持
ljzn
粉丝 30
博文 69
码字总数 96245
作品 0
南平
程序员
私信 提问
Elixir学习笔记(模型匹配、控制语句)

模型匹配 模式匹配是 Elixir 很强大的特性,它允许我们匹配简单值、数据结构、甚至函数。 匹配运算符 在Elixir中,运算符实际上叫做 匹配运算符。通过这个匹配操作符,我们可以赋值和匹配值。...

程序员小哥哥
2018/04/12
0
0
Elixir 学习资源

Elixir 官网 getting started官方入门学习资源 官方文档 hex 包管理系统 elixir sips 比较不错视频课程 Elixir China 中文论坛 官方wiki Elixir by Example Awesome Elixir Elixir Quiz 通过...

lidashuang
2017/11/29
0
0
elixir官方教程Mix与OTP(一) Mix入门

Mix入门 我们的第一个项目 编辑项目 执行测试 环境 探索 在本教程中,我们将学习如何构建一个完整的Elixir应用,包括监督树,配置,测试等等. 这个应用的功能是分布式键值仓库.我们将把键值对安排...

ljzn
2016/08/07
1K
2
elixir官方入门教程 别名,要求与进口

别名,要求与进口 别名 要求 进口 使用 理解别名 模块嵌套 群体别名/进口/要求/使用 为了方便软件复用,Elixir提供了三个命令(,和)外加一个宏,简介如下: 现在我们将详细探索它们.记住前三条之所...

ljzn
2016/08/04
255
2
elixir官方入门教程 介绍

介绍 安装 交互模式 运行脚本 提出疑问 欢迎! 在本教程中我们将教给你Elixir的基础,语法,如何定义模块,如何操作常用数据结构的特性等等.本章将确保Elixir安装好了,并且你能够成功运行Elixir的...

ljzn
2016/08/06
70
0

没有更多内容

加载失败,请刷新页面

加载更多

类加载机制过程

1.加载。 将代码转换成字节流加载进内存。加载完之后创建一个Class对象,这个对象是访问数据的入口。 2.验证。 JVM规范验证和代码逻辑验证。 3.准备 内存分配和初始化。对static修饰的类变量...

无精疯
20分钟前
1
0
next.js 提示 chunk styles [mini-css-extract-plugin]

会出现css 导入警告 导入两个插件 并在next.config.js 配置 yarn add webpack-filter-warnings-pluginyarn add mini-css-extract-plugin const FilterWarningsPlugin = require('webpack-......

一箭落旄头
28分钟前
1
0
AWS的自动部署codeploy 应用程序规范文件

codedeploy应用程序的规范文件 ECS平台上的应用规范文件: AppSpec file也可以是 YAML 或 JSON 格式的,可以直接写入控制台内的编辑器内。 AppSpec file用于指定: 用于将流量定向到新任务集...

守护-创造
35分钟前
1
0
Confluence 6 超过当前许可证期限进行升级

这个页面将会对你在进行 Confluence 升级的时候超过了当前许可证的期限进行升级的情况。 许可证警告 在升级的过程中,你将会在 Confluence 的应用程序日志(log file)中看到类似下面的错误提...

honeymoose
41分钟前
1
0
JS 调用Angularjs 的方法

// 1. 获取 Controllerlet appElement = document.querySelector('[data-ng-controller=MessagesCtrl]');let scope = angular.element(appElement).scope();// 2. 调用方法scope.l......

Moks角木
56分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部