数据类型
熟悉 Elixir 的不同内置数据类型。
Elixir 是一种动态编程语言。因此,我们不需要为每个变量声明类型,其类型取决于当前所持有的值。在本课程中,我们将学习 Elixir 的基本数据类型:整数、浮点数、布尔值、原子、字符串、列表和元组。以下是 Elixir 中可用数据类型的说明。
内置类型
Elixir 的内置类型如下:
- 值类型:
- 任意大小的整数
- 浮点数
- 原子
- 范围
- 正则表达式
- 系统类型:
- PIDs 和端口
- 引用
- 集合类型:
- 元组
- 列表
- 映射(Maps)
- 二进制数据(Binaries)
函数也是一种类型,但它们有专门的章节进行讲解。
值类型
Elixir 的值类型用于表示数字、名称、范围和正则表达式。
整数
整数字面量可以以十进制(1234)、十六进制(0xcafe)、八进制(0o765)或二进制(0b1010)形式书写。十进制数可以包含下划线(_),通常用于分隔三位一组的大数字,例如一百万可写作 1_000_000(在中国和日本也可能写作 100_0000)。
浮点数
浮点数使用小数点书写,小数点前后都必须至少有一位数字。以下都是有效的浮点字面量:
1.0、0.2456 和 0.314159e1、314159.0e-5。
浮点数采用 IEEE 754 双精度格式,具有约 16 位有效数字,最大指数约为 10³⁰⁸。
原子
原子是代表某个名称的常量。我们通过在前面加冒号(:)来书写原子,后面可以跟一个原子标识符或 Elixir 操作符。
原子标识符由 UTF-8 字符、数字、下划线 _ 和 @ 组成,可以以感叹号或问号结尾。
我们也可以通过将冒号后的字符用双引号括起来,创建包含任意字符的原子。
以下都是原子的例子:
:fred、:is_binary?、:var@2、:<>、:===、:"func/3"、:"long john silver"。
原子的名称就是它的值。两个同名的原子总是相等的,即使它们是由相隔大洋的两台计算机上的不同应用程序创建的。
范围
范围表示为 start..end,其中 start 和 end 都是整数。例如 1..9 表示从 1 到 9 的范围。
正则表达式
Elixir 支持正则表达式字面量,写法为 ~r{regexp} 或 ~r{regexp}opts。我们可以选择任意非字母数字字符作为分隔符。有些人出于怀旧原因使用 ~r/.../,但括号形式更方便。可以在正则表达式字面量后添加一个或多个单字符选项,这些选项会改变匹配行为或增加功能。
| 选项 | 含义 |
|---|---|
f | 强制模式从多行字符串的第一行开始匹配。 |
i | 使匹配不区分大小写。 |
m | 如果待匹配的字符串包含多行,则 ^ 和 $ 分别匹配每行的开头和结尾;\A 和 \z 仍匹配整个字符串的开头和结尾。 |
s | 允许 . 匹配任意换行符。 |
U | 默认情况下,* 和 + 等修饰符是贪婪的,尽可能多地匹配。U 修饰符使其变为非贪婪,仅匹配最少内容。 |
u | 启用 Unicode 特定的模式,如 \p。 |
x | 启用扩展模式,忽略空白字符和注释(# 到行尾)。 |
系统类型
这些类型反映了底层 Erlang 虚拟机中的资源。
PIDs 和端口
PID 是对本地或远程进程的引用,端口 是对外部资源的引用,通常是应用程序之外的资源。当前进程的 PID 可通过调用 self 获取。当我们启动新进程时,会生成新的 PID。
引用
函数 make_ref 会创建一个全局唯一的引用,没有任何其他引用会与之相等。
集合类型
我们之前看到的类型在其他编程语言中也很常见。现在进入更独特的类型。Elixir 的集合可以存储任意类型的值,包括其他集合。
元组
元组是有序的值集合。像所有 Elixir 数据结构一样,一旦创建,元组无法修改。我们用大括号 {} 包围元素,并用逗号分隔。以下是一些元组的例子:
{ 1, 2 }{ok, 42, "next"}{:error, :none}
我们可以在模式匹配中使用元组,例如:
1iex> {status, count, action} = {:ok, 42, "next"} 2{:ok, 42, "next"} 3iex> status 4:ok 5iex> count 642
列表
与其它编程语言不同,Elixir 中的列表并不类似于数组。实际上,元组是 Elixir 最接近传统数组的数据结构。在 Elixir 中,列表本质上是一个链式数据结构。
列表要么为空,要么由一个 head(头)和一个 tail(尾)组成。head 包含一个值,而 tail 本身也是一个列表。
Elixir 提供了一些专门用于列表的操作符。下面我们逐一介绍:
1iex> [1,2,3] ++ [4,5,6] 2[1, 2, 3, 4, 5, 6]
这里 ++ 操作符用于连接两个列表。
1iex> [1, 2, 3, 4] -- [2, 4] 2[1, 3]
这里 -- 操作符用于计算两个列表的差集。
1iex> 1 in [1,2,3,4] 2true
in 操作符用于检查某个元素是否存在于列表中。上述例子中我们判断了 1 是否存在于列表中。
映射(Maps)
映射是一种键值对的集合。映射字面量的写法如下:
%{ key => value, key => value }。
以下是一些映射的例子:
1iex> states = %{ "AL" => "Alabama", "WI" => "Wisconsin" } 2%{"AL" => "Alabama", "WI" => "Wisconsin"}
1iex> colors = %{ :red => 0xff0000, :green => 0x00ff00, :blue => 0x0000ff } 2%{blue: 255, green: 65280, red: 16711680}
注意:为什么同时存在映射和关键字列表?因为映射中同一个键只能有一个条目,而关键字列表允许键重复。映射效率更高,且支持 Elixir 的模式匹配。
二进制数据(Binaries)
当需要按位或字节序列访问数据时,我们需要使用二进制数据。例如,JPEG 和 MP3 文件的头部字段中,一个字节可能编码两个或三个独立的值。二进制字面量用 << 和 >> 包裹。
基本语法是将连续的整数打包成字节:
1iex> bin = << 1, 2 >> 2<<1, 2>> 3iex> byte_size bin 42
动手实践
请在下方终端中尝试上述命令。记得先启动 iex 会话。