在本章中,我们将学习更多关于 Elixir 基本类型:整数、浮点数、布尔值、原子和字符串。其他数据类型,如列表和元组,将在下一章中探讨。
iex>1 # integer
iex>0x1F # integer
iex>1.0 # float
iex>true # boolean
iex>:atom # atom / symbol
iex>"elixir" # string
iex>[1, 2, 3] # list
iex>{1, 2, 3} # tuple
基本算术
打开 iex 并输入以下表达式:
iex>1 + 2
3
iex>5 * 5
25
iex>10 / 2
5.0
请注意,10 / 2 返回的是浮点数 5.0,而不是整数 5。这是意料之中的。在 Elixir 中,运算符 / 始终返回浮点数。如果要执行整数除法或获取除法余数,可以调用 div 和 rem 函数:
iex>div(10, 2)
5
iex>div 10, 2
5
iex>rem 10, 3
1
请注意,Elixir 允许您在调用需要一个或多个参数的函数时删除括号。此功能在编写声明和控制流构造时提供了更清晰的语法。但是,Elixir 开发人员通常更喜欢使用括号。
Elixir 还支持输入二进制、八进制和十六进制数字的快捷方式:
iex>0b1010
10
iex>0o777
511
iex>0x1F
31
浮点数需要一个点,后面跟着至少一个数字,并且还支持科学计数法中的 e:
iex>1.0
1.0
iex>1.0e-10
1.0e-10
Elixir 中的浮点数具有 64 位精度。
您可以调用 round 函数来获取最接近给定浮点数的整数,或者调用 trunc 函数来获取浮点数的整数部分。
iex>round(3.58)
4
iex>trunc(3.58)
3
最后,我们使用不同的数据类型,我们将学习 Elixir 提供的几个谓词函数来检查值的类型。例如,is_integer 可用于检查值是否为整数:
iex>is_integer(1)
true
iex>is_integer(2.0)
false
您还可以使用 is_float 或 is_number 分别检查参数是否是浮点数,或者是整数或浮点数。
识别函数和文档
在我们继续讨论下一个数据类型之前,让我们先讨论一下 Elixir 如何识别函数。
Elixir 中的函数通过其名称和参数数量来识别。函数的参数数量描述了函数所采用的参数数量。从现在开始,我们将在整个文档中使用函数名称及其参数数量来描述函数。trunc/1 标识名为 trunc 并采用 1 个参数的函数,而 trunc/2 标识另一个(不存在的)函数,该函数具有相同的名称,但参数数量为 2。
我们还可以使用此语法来访问文档。Elixir shell 定义了 h 函数,您可以使用它来访问任何函数的文档。例如,输入 h trunc/1 将打印 trunc/1 函数的文档:
iex>h trunc/1
def trunc()
Returns the integer part of number.
h trunc/1 之所以有效,是因为它是在内核模块中定义的。内核模块中的所有函数都会自动导入到我们的命名空间中。在查找给定函数的文档时,您通常还会包含模块名称:
iex>h Kernel.trunc/1
def trunc()
Returns the integer part of number.
您可以使用模块+函数来查找任何内容,包括运算符(尝试 h Kernel.+/2)。调用不带参数的 h 会显示 IEx.Helpers 的文档,其中定义了 h 和其他功能。
布尔值和 nil
Elixir 支持 true 和 false 作为布尔值:
iex>true
true
iex>true == false
false
Elixir 还提供了三个布尔运算符:or/2、and/2 和 not/1。这些运算符是严格的,因为它们期望将计算结果为布尔值(true 或 false)的东西作为其第一个参数:
iex>true and true
true
iex>false or is_boolean(true)
true
提供非布尔值将引发异常:
iex>1 and true
** (BadBooleanError) expected a boolean on left-side of "and", got: 1
or 和 and 是短路运算符。如果左侧不足以确定结果,则仅执行右侧:
iex>false and raise("This error will never be raised")
false
iex>true or raise("This error will never be raised")
true
Elixir 还提供了 nil 的概念,以表示值的缺失,以及一组也操作 nil 的逻辑运算符:||/2、&&/2 和 !/1。对于这些运算符,false 和 nil 被视为"假",所有其他值被视为"真":
or
iex>1 || true
1
iex>false || 11
11
and
iex>nil && 13
nil
iex>true && 17
17
not
iex>!true
false
iex>!1
false
iex>!nil
true
原子
原子是一个常量,其值是其自身名称。其他一些语言称之为符号。它们通常用于枚举不同的值,例如:
iex>:apple
:apple
iex>:orange
:orange
iex>:watermelon
:watermelon
如果原子的名称相等,则它们相等。
iex>:apple == :apple
true
iex>:apple == :orange
false
它们通常用于表达操作的状态,通过使用诸如 :ok 和 :error 之类的值。
布尔值 true 和 false 也是原子:
iex>true == :true
true
iex>is_atom(false)
true
iex>is_boolean(:false)
true
Elixir 允许您跳过原子 false、true 和 nil 的前导 :。
字符串
Elixir 中的字符串由双引号分隔,并且采用 UTF-8 编码:
iex>"hellö"
"hellö"
注意:如果您在 Windows 上运行,则您的终端可能默认不使用 UTF-8。您可以在进入 IEx 之前运行 chcp 65001 来更改当前会话的编码。
您可以使用 <>/2 运算符连接两个字符串:
iex>"hello " <> "world!"
"hello world!"
Elixir 还支持字符串插值:
iex>string = "world"
iex>"hello #{string}!"
"hello world!"
字符串连接要求双方都是字符串,但插值支持任何可以转换为字符串的数据类型:
iex>number = 42
iex>"i am #{number} years old!"
"i am 42 years old!"
字符串中可以有换行符。您可以使用转义序列引入它们:
iex>"hello
...> world"
"hello\nworld"
iex>"hello\nworld"
"hello\nworld"
您可以使用 IO 模块中的 IO.puts/1 函数打印字符串:
iex>IO.puts("hello\nworld")
hello
world
:ok
请注意,IO.puts/1 函数在打印后返回原子 :ok。
Elixir 中的字符串在内部由连续的字节序列(称为二进制)表示:
iex>is_binary("hellö")
true
我们还可以获取字符串中的字节数:
iex>byte_size("hellö")
6
请注意,该字符串中的字节数为 6,即使它有 5 个字素。这是因为字素"ö"在 UTF-8 中需要 2 个字节来表示。我们可以使用 String.length/1 函数根据字素数量获取字符串的实际长度:
iex>String.length("hellö")
5
String 模块包含一组对 Unicode 标准中定义的字符串进行操作的函数:
iex>String.upcase("hellö")
"HELLÖ"
结构比较
Elixir 还提供 ==、!=、<=、>=、< 和 > 作为比较运算符。我们可以比较数字:
iex>1 == 1
true
iex>1 != 2
true
iex>1 < 2
true
但也可以比较原子、字符串、布尔值等:
iex>"foo"=="foo"
true
iex>"foo"=="bar"
false
如果整数和浮点数具有相同的值,则它们的比较结果相同:
iex>1 == 1.0
true
iex>1 == 2.0
false
但是,如果您想区分整数和浮点数(这是这些运算符之间的唯一区别),则可以使用严格比较运算符 === 和 !==:
iex>1 === 1.0
false
Elixir 中的比较运算符可以跨任何数据类型进行比较。我们说这些运算符执行结构比较。有关更多信息,您可以阅读我们关于结构与语义比较的文档。
Elixir 还提供了用于表达集合的数据类型,例如列表和元组,我们将在下文中学习。当我们讨论通过进程实现的并发性和容错性时,我们还将讨论端口、pid 和引用,但这些将在后面的章节中讨论。让我们继续前进。