- Erlang教程
- Erlang - 主页
- Erlang - 概述
- Erlang - 环境
- Erlang - 基本语法
- Erlang-Shell
- Erlang - 数据类型
- Erlang - 变量
- Erlang - 运算符
- Erlang - 循环
- Erlang - 决策
- Erlang - 函数
- Erlang - 模块
- Erlang - 递归
- Erlang - 数字
- Erlang - 字符串
- Erlang - 列表
- Erlang - 文件 I/O
- Erlang - 原子
- Erlang - 地图
- Erlang - 元组
- Erlang - 记录
- Erlang - 异常
- Erlang - 宏
- Erlang - 头文件
- Erlang - 预处理器
- Erlang - 模式匹配
- Erlang - 守卫
- Erlang-BIFS
- Erlang - 二进制文件
- Erlang - 乐趣
- Erlang - 进程
- Erlang - 电子邮件
- Erlang - 数据库
- Erlang - 端口
- Erlang - 分布式编程
- Erlang-OTP
- Erlang - 并发
- Erlang - 性能
- Erlang - 驱动程序
- Erlang - 网络编程
- Erlang 有用资源
- Erlang - 快速指南
- Erlang - 有用的资源
- Erlang - 讨论
Erlang - 快速指南
Erlang - 概述
Erlang 是一种函数式编程语言,也有运行时环境。它的构建方式集成了对并发、分布和容错的支持。Erlang 最初是为了在爱立信的几个大型电信系统中使用而开发的。
Erlang 的第一个版本由 Joe Armstrong、Robert Virding 和 Mike Williams 于 1986 年开发。它最初是爱立信内部的专有语言。它后来于 1998 年作为开源语言发布。Erlang 以及 OTP(Erlang 中的中间件和库的集合)现在由爱立信的 OTP 产品部门支持和维护,广泛称为 Erlang/ OTP。
为什么是二郎?
如果您有以下要求,则应使用 Erlang 来开发您的应用程序 -
应用程序需要处理大量并发活动。
它应该可以轻松地通过计算机网络进行分发。
应该有一种工具可以使应用程序对软件和硬件错误都具有容错能力。
应用程序应该是可扩展的。这意味着它应该能够跨越多个服务器,而几乎不需要任何更改。
它应该可以轻松升级和重新配置,而无需停止和重新启动应用程序本身。
应用程序应该在某些严格的时间范围内响应用户。
Erlang 的官方网站是https://www.erlang.org/。
Erlang - 环境
现在,在开始使用 Erlang 之前,您需要确保系统上运行的是功能齐全的 Erlang 版本。本节将介绍 Erlang 在 Windows 机器上的安装及其后续配置,以开始使用 Erlang。
在继续安装之前,请确保满足以下系统要求。
系统要求
记忆 | 2 GB 内存(推荐) |
---|---|
磁盘空间 | 没有最低要求。最好有足够的存储空间来存储将使用 Erlang 创建的应用程序。 |
操作系统版本 | Erlang 可以安装在 Windows、Ubuntu/Debian、Mac OS X 上。 |
下载 Erlang
要下载 Erlang,必须访问以下网址 - www.erlang.org/downloads。
此页面提供各种下载以及在 Linux 和 Mac 平台上下载和安装该语言所需的步骤。
单击“OTP 18.3 Windows 32 位二进制文件”开始下载 Erlang Windows 安装文件。
Erlang安装
以下步骤详细说明了如何在 Windows 上安装 Erlang -
步骤 1 - 启动在前面部分中下载的安装程序。安装程序启动后,单击运行。
步骤 2 - 单击以下屏幕上的“下一步”接受将安装的默认组件。
步骤 3 - 接受默认安装路径,然后单击下一步。
步骤 4 - 接受将创建的默认“开始”菜单项,然后单击“下一步”。
步骤 5 - 安装完成后,单击“关闭”完成安装。
Erlang配置
安装完成后,需要进行以下配置以确保Erlang开始在系统上运行。
操作系统 | 输出 |
---|---|
Windows | 追加字符串;C:\Program Files(x86)\erl7.2.1\bin 或 C:\Program Files\erl7.2.1\bin 到系统变量 PATH 的末尾。 |
如果您现在打开命令提示符并输入erl,您应该能够获得 erl 命令提示符。
恭喜,您现在已经在笔记本电脑上成功配置了 erl。
在流行的 IDE 上安装插件
Erlang 作为一种编程语言也可以在流行的 IDE 中使用,例如Eclipse 和 IntelliJ。让我们看看如何在这些 IDE 中获取所需的插件,以便您在使用 Erlang 时有更多选择。
在 Eclipse 中安装
步骤 1 - 打开 Eclipse 并单击菜单项Help → Install New Software。
步骤 2 - 输入工作链接https://download.erlide.org/update
然后单击添加。
步骤 3 - 然后系统将提示您输入插件的名称,输入名称为Erlide。单击“确定”。
步骤 4 - 然后 Eclipse 将扫描提供的链接并获取所需的插件。检查插件并单击下一步。
步骤 5 - 在下一个对话框中,Eclipse 将显示将安装的所有组件。点击下一步。
步骤 6 - 在下一个对话框中,Eclipse 将只要求检查正在安装的组件。点击下一步。
步骤 7 - 在下一个对话框中,您只需接受许可协议。最后,单击“完成”按钮。
然后安装将开始,完成后,它将提示您重新启动 Eclipse。
重新启动 Eclipse 后,当您创建项目时,您也将能够看到 Erlang 作为一个选项。
在 IntelliJ 中安装
请按照后续步骤在您的计算机上安装 IntelliJ。
步骤 1 - 打开 IntelliJ 并单击配置 → 插件。
步骤 2 - 在搜索框中输入 Erlang。您将在屏幕右侧看到 Erlang 插件。单击“安装”按钮。
步骤 3 - 安装 Erlang 插件后,系统将提示您重新启动 IDE。
当您重新启动 IDE 并尝试创建新项目时,您将看到创建 Erlang 项目的选项。
Erlang - 基本语法
为了理解Erlang的基本语法,我们首先看一个简单的Hello World程序。
例子
% hello world program -module(helloworld). -export([start/0]). start() -> io:fwrite("Hello, world!\n").
关于上述程序需要注意以下事项 -
% 符号用于向程序添加注释。
模块语句就像在任何编程语言中添加名称空间一样。因此,在这里,我们提到此代码将成为名为helloworld的模块的一部分。
使用导出功能,以便可以使用程序中定义的任何功能。我们正在定义一个名为 start 的函数,为了使用 start 函数,我们必须使用导出语句。/ 0表示我们的函数“start”接受 0 个参数。
我们最终定义了我们的启动函数。这里我们使用另一个名为io的模块,它具有 Erlang 中所需的所有输入输出函数。我们使用fwrite函数将“Hello World”输出到控制台。
上述程序的输出将是 -
输出
Hello, world!
声明的一般形式
在 Erlang 中,您已经看到 Erlang 语言中使用了不同的符号。让我们回顾一下从简单的 Hello World 程序中看到的内容 -
连字符(-)通常与模块、导入和导出语句一起使用。连字符用于为每个语句赋予相应的含义。因此,Hello world 程序的示例如以下程序所示 -
-module(helloworld). -export([start/0]).
每个语句都用点(.)符号分隔。Erlang 中的每个语句都需要以此分隔符结束。Hello world 程序的一个示例如以下程序所示 -
io:fwrite("Hello, world!\n").
斜杠(/)符号与函数一起使用来定义函数接受的参数数量。
-export([start/0]).
模块
在Erlang中,所有的代码都被分成模块。模块由一系列属性和函数声明组成。它就像其他编程语言中的命名空间的概念一样,用于在逻辑上分隔不同的代码单元。
定义模块
模块是用模块标识符定义的。一般语法和示例如下。
句法
-module(ModuleName)
ModuleName需要与文件名相同,减去扩展名.erl。否则代码加载将无法按预期进行。
例子
-module(helloworld)
这些模块将在后续章节中详细介绍,这只是为了让您对如何定义模块有一个基本的了解。
Erlang 中的导入语句
在Erlang中,如果想使用现有Erlang模块的功能,可以使用import语句。以下程序描述了导入语句的一般形式 -
例子
-import (modulename, [functionname/parameter]).
在哪里,
Modulename - 这是需要导入的模块的名称。
functionname/parameter - 模块中需要导入的函数。
让我们更改编写 hello world 程序的方式以使用 import 语句。该示例如以下程序所示。
例子
% hello world program -module(helloworld). -import(io,[fwrite/1]). -export([start/0]). start() -> fwrite("Hello, world!\n").
在上面的代码中,我们使用 import 关键字导入库“io”,特别是fwrite函数。所以现在每当我们调用 fwrite 函数时,我们不必到处提及io模块名称。
Erlang 中的关键字
关键字是 Erlang 中的保留字,不应将其用于除预期目的之外的任何其他目的。以下是 Erlang 中的关键字列表。
后 | 和 | 并且 | 乐队 |
开始 | 不 | 博尔 | BSL |
巴塞尔 | 异或 | 案件 | 抓住 |
条件 | 分区 | 结尾 | 乐趣 |
如果 | 让 | 不是 | 的 |
或者 | 要不然 | 收到 | 雷姆 |
尝试 | 什么时候 | 异或 |
Erlang 中的评论
注释用于记录您的代码。单行注释通过在行中的任意位置使用%符号来标识。以下是相同的示例 -
例子
% hello world program -module(helloworld). % import function used to import the io module -import(io,[fwrite/1]). % export function used to ensure the start function can be accessed. -export([start/0]). start() -> fwrite("Hello, world!\n").
Erlang-Shell
Erlang shell 用于测试表达式。因此,在应用程序本身进行实际测试之前,可以非常轻松地在 shell 中进行测试。
以下示例展示了如何在 shell 中使用加法表达式。这里需要注意的是,表达式需要以点(.)分隔符结束。
该命令执行后,shell 打印出另一个提示符,这次是命令号 2(因为每次输入新命令时命令号都会增加)。
以下函数是 Erlang shell 中最常用的函数。
b() - 打印当前变量绑定。
语法- b().
例如- 以下是如何使用该函数的示例。首先定义一个名为Str的变量,其值为abcd。然后b()用于显示所有绑定变量。
f() - 删除所有当前变量绑定。
语法- f()。
例如- 以下是如何使用该函数的示例。首先定义一个名为 Str 的变量,其值为 abcd。然后使用 f() 删除 Str 变量绑定。然后调用 b() 以确保绑定已成功删除。
f(x) - 删除特定变量的绑定。
语法- f(x)。其中,x – 是需要删除绑定的变量。
例如- 以下是如何使用该函数的示例。首先定义一个名为 Str 和 Str1 的变量。然后使用 f(Str) 删除 Str 变量绑定。然后调用 b() 以确保绑定已成功删除。
h() - 打印 shell 中执行的所有命令的历史列表。
语法- h().
例如- h() 命令的示例,它打印 shell 中执行的命令的历史记录,如以下屏幕截图所示。
History(N) - 将历史列表中保留的先前命令的数量设置为 N。返回先前的数量。默认数量为 20。
语法- 历史记录(N)。其中,N – 是命令历史列表需要限制的数量。
例如- 下面的屏幕截图显示了历史(N)命令的示例。
e(N) - 如果 N 为正,则重复命令 N。如果为负,则重复第 N个先前命令(即 e(-1) 重复先前命令)。
语法- e(N)。其中,N – 是列表中第 N个位置的命令。
例如- e(N) 命令的示例如下所示。由于我们已经执行了 e(-1) 命令,它将执行上一个命令,即历史记录(5)。
Erlang - 数据类型
在任何编程语言中,都需要使用多个变量来存储各种类型的信息。变量只不过是用于存储值的保留内存位置。这意味着当您创建变量时,您会在内存中保留一些空间来存储与该变量关联的值。
您可能喜欢存储各种数据类型的信息,如字符串、字符、宽字符、整数、浮点、布尔值等。操作系统根据变量的数据类型分配内存并决定保留的内容可以存储记忆。
内置数据类型
Erlang 提供了多种内置数据类型。以下是 Erlang 中定义的数据类型列表 -
Number - 在 Erlang 中,有两种类型的数字文字:整数和浮点数。
Atomics- Atomics是一个文字,一个有名称的常量。如果Atomics不以小写字母开头或者包含除字母数字字符、下划线 (_) 或 @ 之外的其他字符,则Atomics将用单引号 (') 括起来。
Boolean - Erlang 中的布尔数据类型是两个保留Atomics:true 和 false。
位字符串- 位字符串用于存储非类型化内存区域。
元组- 元组是具有固定数量项的复合数据类型。元组中的每个术语称为一个元素。元素的数量被称为元组的大小。
映射- 映射是一种复合数据类型,具有可变数量的键值关联。映射中的每个键值关联称为关联对。该对的键和值部分称为元素。关联对的数量被称为地图的大小。
列表- 列表是一种具有可变数量术语的复合数据类型。列表中的每个术语称为一个元素。元素的数量称为列表的长度。
注意- 您会惊讶地发现您在上面列表中的任何位置都看不到 String 类型。这是因为 Erlang 中没有专门定义的字符串数据类型。但我们将在后续章节中看到如何使用字符串。
以下是如何使用每种数据类型的示例。同样,每种数据类型将在后续章节中详细讨论。这只是为了让您熟悉上述数据类型的简要描述。
数字
以下程序显示了如何使用数字数据类型的示例。该程序显示 2 个整数的加法。
例子
-module(helloworld). -export([start/0]). start() -> io:fwrite("~w",[1+1]).
上述程序的输出将是 -
输出
2
Atomics
Atomics应以小写字母开头,可以包含小写和大写字符、数字、下划线(_)和“at”符号(@)。我们还可以将Atomics用单引号引起来。
以下程序显示了如何使用Atomics数据类型的示例。在这个程序中,我们创建一个名为atom1的Atomics。
例子
-module(helloworld). -export([start/0]). start() -> io:fwrite(atom1).
上述程序的输出将是 -
输出
atom1
布尔值
以下程序显示了如何使用布尔数据类型的示例。此示例对 2 个整数进行比较,并将结果布尔值打印到控制台。
例子
-module(helloworld). -export([start/0]). start() -> io:fwrite(2 =< 3).
上述程序的输出将是 -
输出
true
位串
以下程序显示了如何使用位串数据类型的示例。该程序定义了一个由 2 位组成的位串。binary_to_list是 Erlang 中定义的内置函数,可用于将位字符串转换为列表。
例子
-module(helloworld). -export([start/0]). start() -> Bin1 = <<10,20>>, X = binary_to_list(Bin1), io:fwrite("~w",[X]).
上述程序的输出将是 -
输出
[10,20]
元组
以下程序显示了如何使用元组数据类型的示例。
这里我们定义一个有 3 项的元组 P。tuple_size是Erlang中定义的内置函数,可用于确定元组的大小。
例子
-module(helloworld). -export([start/0]). start() -> P = {john,24,{june,25}} , io:fwrite("~w",[tuple_size(P)]).
上述程序的输出将是 -
输出
3
地图
以下程序显示了如何使用 Map 数据类型的示例。
这里我们定义了一个Map M1,它有 2 个映射。map_size是Erlang中定义的内置函数,可用于确定地图的大小。
例子
-module(helloworld). -export([start/0]). start() -> M1 = #{name=>john,age=>25}, io:fwrite("~w",[map_size(M1)]).
上述程序的输出将是 -
输出
2
列表
以下程序显示了如何使用列表数据类型的示例。
这里我们定义一个包含 3 个项目的列表 L。length是Erlang中定义的内置函数,可用于确定列表的大小。
例子
-module(helloworld). -export([start/0]). start() -> L = [10,20,30] , io:fwrite("~w",[length(L)]).
上述程序的输出将是 -
输出
3
Erlang - 变量
在 Erlang 中,所有变量都与“=”语句绑定。所有变量都需要以大写字符开头。在其他编程语言中,“=”符号用于赋值,但在 Erlang 中则不然。如上所述,变量是使用“=”语句定义的。
在 Erlang 中需要注意的一件关键事情是变量是不可变的,这意味着为了改变变量的值,需要将其销毁并再次重新创建。
Erlang 中的以下基本变量在上一章中进行了解释 -
数字- 用于表示整数或浮点数。一个例子是 10。
Boolean - 这表示一个布尔值,可以是 true 或 false。
位字符串- 位字符串用于存储非类型化内存区域。一个例子是<<40,50>>。
元组- 元组是具有固定数量项的复合数据类型。一个例子是{40,50}。
映射- 映射是一种复合数据类型,具有可变数量的键值关联。映射中的每个键值关联称为关联对。一个例子是 {type=>person,age=>25}。
列表- 列表是一种具有可变数量术语的复合数据类型。一个例子是[40,40]。
变量声明
定义变量的一般语法如下 -
句法
var-name = var-value
在哪里,
var-name - 这是变量的名称。
var-value - 这是绑定到变量的值。
以下是变量声明的示例 -
例子
-module(helloworld). -export([start/0]). start() -> X = 40, Y = 50, Result = X + Y, io:fwrite("~w",[Result]).
在上面的示例中,我们有 2 个变量,一个是 X,它绑定到值 40,下一个是 Y,它绑定到值 50。另一个名为 Result 的变量绑定到 X 和 Y 的加法。
上述程序的输出将是 -
输出
90
命名变量
正如所讨论的,变量名称必须以大写字母开头。让我们举一个以小写形式声明的变量的示例。
例子
-module(helloworld). -export([start/0]). start() -> X = 40, Y = 50, result = X + Y, io:fwrite("~w",[Result]).
如果您尝试编译上述程序,您将收到以下编译时错误。
输出
helloworld.erl:8: variable 'Result' is unbound
其次,所有变量只能赋值一次。让我们举一个多次分配变量的例子。
例子
-module(helloworld). -export([start/0]). start() -> X = 40, Y = 50, X = 60, io:fwrite("~w",[X]).
如果您尝试编译上述程序,您将收到以下编译时错误。
输出
helloworld.erl:6: Warning: variable 'Y' is unused helloworld.erl:7: Warning: no clause will ever match helloworld.erl:7: Warning: the guard for this clause evaluates to 'false'
打印变量
在本节中,我们将讨论如何使用打印变量的各种功能。
使用 io:fwrite 函数
您可能已经在上述所有程序中看到过这个 (io:fwrite) 的使用。fwrite函数是 io 模块或 Erlang 的一部分,可用于输出程序中变量的值。
以下示例显示了可与 fwrite 语句一起使用的更多参数。
例子
-module(helloworld). -export([start/0]). start() -> X = 40.00, Y = 50.00, io:fwrite("~f~n",[X]), io:fwrite("~e",[Y]).
上述程序的输出将是 -
输出
40.000000 5.00000e+1
关于上述程序,应注意以下几点。
~ - 该字符表示需要对输出进行一些格式化。
~f - 参数是一个浮点数,写作 [-]ddd.ddd,其中精度是小数点后的位数。默认精度为 6,且不能小于 1。
~n - 这是打印到新行。
~e - 参数是一个浮点数,写为 [-]d.ddde+-ddd,其中精度是写入的位数。默认精度为 6,且不能小于 2。
Erlang - 运算符
运算符是告诉编译器执行特定数学或逻辑操作的符号。
Erlang 有以下类型的运算符 -
- 算术运算符
- 关系运算符
- 逻辑运算符
- 按位运算符
算术运算符
Erlang 语言与任何语言一样支持普通算术运算符。以下是 Erlang 中可用的算术运算符。
操作员 | 描述 | 例子 |
---|---|---|
+ | 两个操作数相加 | 1 + 2 将得到 3 |
- | 从第一个操作数中减去第二个操作数 | 1 - 2 将给出 -1 |
* | 两个操作数相乘 | 2 * 2 将得到 4 |
/ | 分子除以分母 | 2 / 2 将给出 1 |
雷姆 | 第一个数除以第二个数的余数 | 3 rem 2 将给出 1 |
分区 | div 组件将执行除法并返回整数组件。 | 3 div 2 将给出 1 |
关系运算符
关系运算符允许对对象进行比较。以下是 Erlang 中可用的关系运算符。
操作员 | 描述 | 例子 |
---|---|---|
== | 测试两个对象之间的相等性 | 2 = 2 将给出 true |
/= | 测试两个对象之间的差异 | 3 /= 2 将给出 true |
< | 检查左侧对象是否小于右侧操作数。 | 2 < 3 将给出 true |
=< | 检查左侧对象是否小于或等于右侧操作数。 | 2 =<3 将给出 true |
> | 检查左侧对象是否大于右侧操作数。 | 3 > 2 将给出 true |
>= | 检查左侧对象是否大于或等于右侧操作数。 | 3 >= 2 将给出 true |
逻辑运算符
这些逻辑运算符用于计算布尔表达式。以下是 Erlang 中可用的逻辑运算符。
操作员 | 描述 | 例子 |
---|---|---|
或者 | 这是逻辑“或”运算符 | true 或 true 将给出 true |
和 | 这是逻辑“与”运算符 | 真与假将给出假 |
不是 | 这是逻辑“非”运算符 | 不假将给真 |
异或 | 这是逻辑异或“异或”运算符 | true 异或 false 将给出 true |
按位运算符
Erlang 提供了四种按位运算符。以下是 Erlang 中可用的按位运算符。
先生。 | 运算符及描述 |
---|---|
1 |
乐队 这是按位“与”运算符 |
2 |
博尔 这是按位“或”运算符 |
3 |
异或 这是按位“异或”或异或运算符 |
4 |
不 这是按位求反运算符 |
以下是展示这些运算符的真值表 -
p | q | 质与问 | p| q | p^q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
运算符优先级
下表按优先级降序显示了 Erlang 运算符的运算符优先级及其关联性。运算符优先级和结合性用于确定无括号表达式中的计算顺序。
运营商 | 关联性 |
---|---|
: | |
# | |
不,不 | |
/,*,div,rem,band,和 | 左结合 |
+、-、bor、bxor、or、xor | 左结合 |
==,/=,=<,<,>=,> |
Erlang - 循环
Erlang 是一种函数式编程语言,关于所有函数式编程语言需要记住的是它们不提供任何循环结构。相反,函数式编程依赖于一个称为递归的概念。
while 语句实现
由于 Erlang 中没有直接的 while 语句可用,因此必须使用 Erlang 中可用的递归技术来执行 while 语句实现。
我们将尝试遵循与其他编程语言相同的 while 循环实现。以下是将遵循的一般流程。
让我们看一个例子,了解如何使用递归在 Erlang 中实现while循环。
例子
-module(helloworld). -export([while/1,while/2, start/0]). while(L) -> while(L,0). while([], Acc) -> Acc; while([_|T], Acc) -> io:fwrite("~w~n",[Acc]), while(T,Acc+1). start() -> X = [1,2,3,4], while(X).
上述程序需要注意以下要点 -
定义一个名为 while 的递归函数,它将模拟 while 循环的实现。
将变量 X 中定义的值列表输入到我们的 while 函数中作为示例。
while 函数获取每个列表值并将中间值存储在变量“Acc”中。
然后为列表中的每个值递归调用 while 循环。
上述代码的输出将是 -
输出
0 1 2 3
对于声明
由于 Erlang 中没有直接的for语句,因此必须使用 Erlang 中的递归技术来执行for语句实现。
我们将尝试遵循与其他编程语言相同的for循环实现。以下是应遵守的一般流程。
让我们看一个例子,了解如何使用递归在 Erlang 中实现for循环。
例子
-module(helloworld). -export([for/2,start/0]). for(0,_) -> []; for(N,Term) when N > 0 -> io:fwrite("Hello~n"), [Term|for(N-1,Term)]. start() -> for(5,1).
上述程序需要注意以下要点 -
我们正在定义一个递归函数来模拟for 循环的实现。
我们在“for”函数中使用一个防护来确保 N 的值或限制是正值。
我们通过在每次递归时减少 N 的值来递归调用 for 函数。
上述代码的输出将是 -
输出
Hello Hello Hello Hello Hello
Erlang - 决策
决策结构要求程序员指定程序要评估或测试的一个或多个条件,以及在条件确定为 true 时要执行的一条或多条语句,以及可选的在条件成立时要执行的其他语句。条件被确定为false。
以下是大多数编程语言中典型决策结构的一般形式 -
Erlang 编程语言提供以下类型的决策语句。
先生。 | 声明及说明 |
---|---|
1 |
if语句由一个布尔表达式后跟一个或多个语句组成。 |
2 |
if表达式还允许同时计算多个表达式。 |
3 |
您可以在另一个if或else if语句中使用一个if或else if语句。 |
4 |
它可用于根据 case 语句的输出执行表达式。 |
Erlang - 函数
Erlang 被称为函数式编程语言,因此您会期望看到大量强调函数在 Erlang 中如何工作的内容。本章涵盖了使用 Erlang 中的函数可以完成的所有操作。
定义函数
函数声明的语法如下 -
句法
FunctionName(Pattern1… PatternN) -> Body;
在哪里,
FunctionName - 函数名称是一个Atomics。
Pattern1…PatternN - 每个参数都是一个模式。参数的数量 N 是函数的元数。函数由模块名称、函数名称和元数唯一定义。也就是说,两个具有相同名称且位于同一模块中但具有不同参数的函数是两个不同的函数。
主体- 子句主体由一系列用逗号 (,) 分隔的表达式组成:
以下程序是使用函数的简单示例 -
例子
-module(helloworld). -export([add/2,start/0]). add(X,Y) -> Z = X+Y, io:fwrite("~w~n",[Z]). start() -> add(5,6).
关于上述程序,应注意以下几点 -
我们定义了两个函数,一个称为add,它有 2 个参数,另一个是start函数。
这两个函数都是用导出函数定义的。如果我们不这样做,我们将无法使用该功能。
一个函数可以在另一个函数内部调用。这里我们从 start 函数调用 add 函数。
上述程序的输出将是 -
输出
11
匿名函数
匿名函数是一个没有与其关联的名称的函数。Erlang 有能力定义匿名函数。以下程序是匿名函数的示例。
例子
-module(helloworld). -export([start/0]). start() -> Fn = fun() -> io:fwrite("Anonymous Function") end, Fn().
关于上面的例子需要注意以下几点 -
匿名函数是用fun()关键字定义的。
该函数被分配给一个名为 Fn 的变量。
通过变量名调用函数。
上述程序的输出将是 -
输出
Anonymous Function
具有多个参数的函数
Erlang 函数可以用零个或多个参数来定义。函数重载也是可能的,其中您可以多次定义具有相同名称的函数,只要它们具有不同数量的参数即可。
在以下示例中,函数 demo 的每个函数定义都使用多个参数进行定义。
例子
-module(helloworld). -export([add/2,add/3,start/0]). add(X,Y) -> Z = X+Y, io:fwrite("~w~n",[Z]). add(X,Y,Z) -> A = X+Y+Z, io:fwrite("~w~n",[A]). start() -> add(5,6), add(5,6,6).
在上面的程序中,我们定义了两次 add 函数。但是第一个 add 函数的定义接受两个参数,第二个函数接受三个参数。
上述程序的输出将是 -
输出
11 17
具有保护序列的函数
Erlang 中的函数还具有保护序列的能力。这些只不过是表达式,只有当计算结果为 true 时才会导致函数运行。
具有保护序列的函数的语法如以下程序所示。
句法
FunctionName(Pattern1… PatternN) [when GuardSeq1]-> Body;
在哪里,
FunctionName - 函数名称是一个Atomics。
Pattern1…PatternN - 每个参数都是一个模式。参数的数量 N 是函数的元数。函数由模块名称、函数名称和元数唯一定义。也就是说,两个具有相同名称且位于同一模块中但具有不同参数的函数是两个不同的函数。
主体- 子句主体由一系列用逗号 (,) 分隔的表达式组成。
GuardSeq1 - 这是调用函数时评估的表达式。
以下程序是使用带有保护序列的函数的简单示例。
例子
-module(helloworld). -export([add/1,start/0]). add(X) when X>3 -> io:fwrite("~w~n",[X]). start() -> add(4).
上述程序的输出是 -
输出
4
如果 add 函数被调用为add(3),程序将导致错误。
Erlang - 模块
模块是在单个文件中以单个名称重新组合的一组函数。此外,Erlang 中的所有函数都必须在模块中定义。
大多数基本功能(如算术、逻辑和布尔运算符)已经可用,因为默认模块是在程序运行时加载的。您将使用的模块中定义的每个其他函数都需要以Module:Function (Arguments)的形式调用。
定义模块
使用模块,您可以声明两种事物:函数和属性。属性是描述模块本身的元数据,例如模块的名称、对外可见的功能、代码的作者等。这种元数据很有用,因为它向编译器提供了有关如何完成其工作的提示,还因为它使人们可以从编译的代码中检索有用的信息,而无需查阅源代码。
函数声明的语法如下 -
句法
-module(modulename)
其中,modulename是模块的名称。这必须是模块中代码的第一行。
以下程序显示了名为helloworld 的模块的示例。
例子
-module(helloworld). -export([start/0]). start() -> io:fwrite("Hello World").
上述程序的输出是 -
输出
Hello World
模块属性
模块属性定义模块的某个属性。模块属性由标签和值组成。
属性的一般语法是 -
句法
-Tag(Value)
以下程序显示了如何使用该属性的示例 -
例子
-module(helloworld). -author("TutorialPoint"). -version("1.0"). -export([start/0]). start() -> io:fwrite("Hello World").
上面的程序定义了 2 个自定义属性,称为作者和版本,分别包含程序作者和程序版本号。
上述程序的输出是 -
输出
Hello World
预建属性
Erlang 有一些可以附加到模块的预构建属性。让我们来看看它们。
出口
Exports 属性将获取函数和数量的列表来导出以供其他模块使用。它将定义模块接口。我们已经在之前的所有示例中看到了这一点。
句法
export([FunctionName1/FunctionArity1,.,FunctionNameN/FunctionArityN])
在哪里,
FunctionName - 这是程序中函数的名称。
FunctionArity - 这是与函数关联的参数数量。
例子
-module(helloworld). -author("TutorialPoint"). -version("1.0"). -export([start/0]). start() -> io:fwrite("Hello World").
上述程序的输出将是 -
输出
Hello World
进口
import 属性用于从另一个模块导入函数以将其作为本地使用。
句法
-import (modulename , [functionname/parameter]).
在哪里,
Modulename - 这是需要导入的模块的名称。
函数名称/参数- 模块中需要导入的函数。
例子
-module(helloworld). -import(io,[fwrite/1]). -export([start/0]). start() -> fwrite("Hello, world!\n").
在上面的代码中,我们使用 import 关键字导入库“io”,特别是 fwrite 函数。因此,现在每当我们调用 fwrite 函数时,我们不必到处提及 io 模块名称。
上述程序的输出将是 -
输出
Hello, world!
Erlang - 递归
递归是Erlang的重要组成部分。首先让我们看看如何通过实现阶乘程序来实现简单的递归。
例子
-module(helloworld). -export([fac/1,start/0]). fac(N) when N == 0 -> 1; fac(N) when N > 0 -> N*fac(N-1). start() -> X = fac(4), io:fwrite("~w",[X]).
关于上述程序需要注意以下事项 -
我们首先定义一个名为 fac(N) 的函数。
我们可以通过递归调用 fac(N) 来定义递归函数。
上述程序的输出是 -
输出
24
实用的递归方法
在本节中,我们将详细了解不同类型的递归及其在 Erlang 中的用法。
长度递归
可以通过一个简单的示例来了解更实用的递归方法,该示例用于确定列表的长度。列表可以有多个值,例如 [1,2,3,4]。让我们使用递归来看看如何获得列表的长度。
例子
-module(helloworld). -export([len/1,start/0]). len([]) -> 0; len([_|T]) -> 1 + len(T). start() -> X = [1,2,3,4], Y = len(X), io:fwrite("~w",[Y]).
关于上述程序需要注意以下事项 -
第一个函数len([])用于列表为空的特殊情况。
用于匹配一个或多个元素的列表的[H|T]模式,长度为 1 的列表将定义为[X|[]],长度为 2 的列表将定义为[X|[Y|[ ]]]。请注意,第二个元素本身就是一个列表。这意味着我们只需要计算第一个元素,函数就可以在第二个元素上调用自身。给定列表中每个值的长度均为 1。
上述程序的输出将是 -
输出
4
尾递归
要了解尾递归的工作原理,让我们了解上一节中的以下代码的工作原理。
句法
len([]) -> 0; len([_|T]) -> 1 + len(T).
1 + len(Rest) 的答案需要 len(Rest) 的答案才能找到。然后,函数 len(Rest) 本身需要找到另一个函数调用的结果。添加的内容会一直堆积起来,直到找到最后一个,然后才能计算出最终的结果。
尾递归的目的是通过在发生操作时减少操作的堆积来消除操作的堆积。
为了实现这一点,我们需要在函数中保存一个额外的临时变量作为参数。上述临时变量有时称为累加器,充当存储计算结果的位置,以限制调用的增长。
让我们看一个尾递归的例子 -
例子
-module(helloworld). -export([tail_len/1,tail_len/2,start/0]). tail_len(L) -> tail_len(L,0). tail_len([], Acc) -> Acc; tail_len([_|T], Acc) -> tail_len(T,Acc+1). start() -> X = [1,2,3,4], Y = tail_len(X), io:fwrite("~w",[Y]).
上述程序的输出是 -
输出
4
复制
让我们看一个递归的例子。这一次,让我们编写一个函数,该函数将整数作为其第一个参数,然后将任何其他项作为其第二个参数。然后,它将创建一个列表,其中包含由整数指定的尽可能多的术语副本。
让我们看一下这个例子 -
-module(helloworld). -export([duplicate/2,start/0]). duplicate(0,_) -> []; duplicate(N,Term) when N > 0 -> io:fwrite("~w,~n",[Term]), [Term|duplicate(N-1,Term)]. start() -> duplicate(5,1).
上述程序的输出将是 -
输出
1, 1, 1, 1, 1,
列表反转
在 Erlang 中使用递归没有任何限制。现在让我们快速看看如何使用递归来反转列表的元素。可以使用以下程序来完成此操作。
例子
-module(helloworld). -export([tail_reverse/2,start/0]). tail_reverse(L) -> tail_reverse(L,[]). tail_reverse([],Acc) -> Acc; tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]). start() -> X = [1,2,3,4], Y = tail_reverse(X), io:fwrite("~w",[Y]).
上述程序的输出将是 -
输出
[4,3,2,1]
关于上述程序需要注意以下事项 -
我们再次使用临时变量的概念将 List 的每个元素存储在名为 Acc 的变量中。
然后我们递归地调用tail_reverse,但这一次,我们确保最后一个元素首先放入新列表中。
然后,我们对列表中的每个元素递归调用 tail_reverse。
Erlang - 数字
在 Erlang 中,有两种类型的数字文字:整数和浮点数。以下是一些示例,展示了如何在 Erlang 中使用整数和浮点数。
整数- 以下程序显示了如何将数字数据类型用作整数的示例。该程序显示 2 个整数的加法。
例子
-module(helloworld). -export([start/0]). start() -> io:fwrite("~w",[1+1]).
上述程序的输出如下 -
输出
2
Float - 以下程序显示了如何将数字数据类型用作浮点的示例。该程序显示 2 个整数的加法。
例子
-module(helloworld). -export([start/0]). start() -> io:fwrite("~w",[1.1+1.2]).
上述程序的输出如下 -
输出
2.3
显示浮点数和指数
当使用fwrite方法将值输出到控制台时,可以使用格式化参数来将数字输出为浮点数或指数数。让我们看看如何实现这一目标。
例子
-module(helloworld). -export([start/0]). start() -> io:fwrite("~f~n",[1.1+1.2]), io:fwrite("~e~n",[1.1+1.2]).
上述程序的输出如下 -
输出
2.300000 2.30000e+0
关于上述程序需要注意以下关键事项 -
当指定 ~f 选项时,意味着参数是一个浮点数,写作[-]ddd.ddd,其中精度是小数点后的位数。默认精度为 6。
当指定 ~e 选项时,意味着参数是一个浮点数,写为[-]d.ddde+-ddd,其中精度是写入的位数。默认精度为 6。
数字的数学函数
Erlang 中可以使用以下数学函数来表示数字。请注意,Erlang 的所有数学函数都存在于数学库中。因此,以下所有示例都将使用 import 语句导入数学库中的所有方法。