查看源代码 Erlang 库
Elixir 提供了与 Erlang 库的出色互操作性。实际上,Elixir 不鼓励简单地包装 Erlang 库,而是更倾向于直接与 Erlang 代码交互。在本节中,我们将介绍一些在 Elixir 中找不到的最常见和最实用的 Erlang 功能。
Erlang 模块的命名约定与 Elixir 中不同,以小写字母开头。在这两种情况下,模块名称都是原子,我们通过调度到模块名称来调用函数。
iex> is_atom(String)
true
iex> String.first("hello")
"h"
iex> is_atom(:binary)
true
iex> :binary.first("hello")
104
随着您对 Elixir 的掌握越来越熟练,您可能希望更详细地探索 Erlang 的 STDLIB 参考手册。
二进制模块
内置的 Elixir String 模块处理 UTF-8 编码的二进制数据。当您处理不一定为 UTF-8 编码的二进制数据时, :binary
模块 很有用。
iex> String.to_charlist("Ø")
[216]
iex> :binary.bin_to_list("Ø")
[195, 152]
以上示例显示了区别;String
模块返回 Unicode 码位,而 :binary
处理原始数据字节。
格式化文本输出
Elixir 不包含类似于 C 和其他语言中 printf
的函数。幸运的是,Erlang 标准库函数 :io.format/2
和 :io_lib.format/2
可供使用。第一个格式化为终端输出,而第二个格式化为 iolist。格式说明符与 printf
不同,有关详细信息,请参阅 Erlang 文档。
iex> :io.format("Pi is approximately given by:~10.3f~n", [:math.pi])
Pi is approximately given by: 3.142
:ok
iex> to_string(:io_lib.format("Pi is approximately given by:~10.3f~n", [:math.pi]))
"Pi is approximately given by: 3.142\n"
加密模块
:crypto
模块 包含哈希函数、数字签名、加密等
iex> Base.encode16(:crypto.hash(:sha256, "Elixir"))
"3315715A7A3AD57428298676C5AE465DADA38D951BDFAC9348A8A31E9C7401CB"
:crypto
模块是随 Erlang 一起提供的 :crypto
应用程序的一部分。这意味着您必须将 :crypto
应用程序列为项目配置中的附加应用程序。为此,请编辑您的 mix.exs
文件以包含以下内容
def application do
[extra_applications: [:crypto]]
end
任何不属于 :kernel
或 :stdlib
Erlang 应用程序的模块都必须在您的 mix.exs
中显式列出其应用程序。您可以在 Erlang 文档中找到任何 Erlang 模块的应用程序名称,该名称位于侧边栏中 Erlang 徽标的正下方。
有向图模块
:digraph
和 :digraph_utils
模块包含用于处理由顶点和边构成的有向图的函数。在构建图形后,其中的算法将帮助您找到例如两个顶点之间的最短路径或图形中的循环。
给定三个顶点,找到从第一个到最后一个的最短路径。
iex> digraph = :digraph.new()
iex> coords = [{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}]
iex> [v0, v1, v2] = (for c <- coords, do: :digraph.add_vertex(digraph, c))
iex> :digraph.add_edge(digraph, v0, v1)
iex> :digraph.add_edge(digraph, v1, v2)
iex> :digraph.get_short_path(digraph, v0, v2)
[{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}]
请注意, :digraph
中的函数会就地修改图形结构,这是因为它们作为 ETS 表实现,将在下面解释。
Erlang 术语存储
模块 :ets
和 :dets
分别处理大型数据结构在内存或磁盘中的存储。
ETS 允许您创建一个包含元组的表。默认情况下,ETS 表是受保护的,这意味着只有所有者进程可以写入表,但任何其他进程都可以读取。ETS 有一些功能允许将表用作简单的数据库、键值存储或缓存机制。
ets
模块中的函数将修改表的状体作为副作用。
iex> table = :ets.new(:ets_test, [])
# Store as tuples with {name, population}
iex> :ets.insert(table, {"China", 1_374_000_000})
iex> :ets.insert(table, {"India", 1_284_000_000})
iex> :ets.insert(table, {"USA", 322_000_000})
iex> :ets.i(table)
<1 > {<<"India">>,1284000000}
<2 > {<<"USA">>,322000000}
<3 > {<<"China">>,1374000000}
数学模块
:math
模块包含涵盖三角函数、指数函数和对数函数的常用数学运算。
iex> angle_45_deg = :math.pi() * 45.0 / 180.0
iex> :math.sin(angle_45_deg)
0.7071067811865475
iex> :math.exp(55.0)
7.694785265142018e23
iex> :math.log(7.694785265142018e23)
55.0
队列模块
:queue
模块提供了一种数据结构,它高效地实现了(双端)FIFO(先进先出)队列。
iex> q = :queue.new
iex> q = :queue.in("A", q)
iex> q = :queue.in("B", q)
iex> {value, q} = :queue.out(q)
iex> value
{:value, "A"}
iex> {value, q} = :queue.out(q)
iex> value
{:value, "B"}
iex> {value, q} = :queue.out(q)
iex> value
:empty
随机数模块
:rand
包含用于返回随机值和设置随机种子 的函数。
iex> :rand.uniform()
0.8175669086010815
iex> _ = :rand.seed(:exs1024, {123, 123534, 345345})
iex> :rand.uniform()
0.5820506340260994
iex> :rand.uniform(6)
6
zip 和 zlib 模块
:zip
模块允许您将 ZIP 文件读写到磁盘或内存,以及提取文件信息。
此代码计算 ZIP 文件中的文件数量
iex> :zip.foldl(fn _, _, _, acc -> acc + 1 end, 0, :binary.bin_to_list("file.zip"))
{:ok, 633}
:zlib
模块处理 zlib 格式的数据压缩,如 Unix 系统中 gzip
命令行实用程序中发现的那样。
iex> song = "
...> Mary had a little lamb,
...> His fleece was white as snow,
...> And everywhere that Mary went,
...> The lamb was sure to go."
iex> compressed = :zlib.compress(song)
iex> byte_size(song)
110
iex> byte_size(compressed)
99
iex> :zlib.uncompress(compressed)
"\nMary had a little lamb,\nHis fleece was white as snow,\nAnd everywhere that Mary went,\nThe lamb was sure to go."
学习 Erlang
如果您想更深入地了解 Erlang,以下列出了涵盖 Erlang 基础知识及其更高级功能的在线资源
这个 Erlang 语法:速成课程 简要介绍了 Erlang 的语法。每个代码片段都附有 Elixir 中的等效代码。这是一个让您不仅可以接触到 Erlang 的语法,还可以回顾您对 Elixir 的了解的机会。
学习 Erlang 为伟大的善而学习! 是对 Erlang、其设计原则、标准库、最佳实践等等的极佳介绍。在阅读完上面提到的速成课程后,您可以跳过本书前几章,这些章节主要介绍语法。当您到达 并发编程指南 章节时,真正的乐趣就开始了。
最后一步是看看在调试时可能用到的现有 Elixir(和 Erlang)库。