21-Erlang库

正如前文所言,Elixir是基于Erlang实现的编程语言。 对于Erlang语言库,Elixir提供了完善的交互能力。 而且,实际上,Elixir不只是简单地对Erlang库功能进行语言上的包装(是的,没有Elixir版本的对应Erlang库函数), 而是直接连接Erlang代码(因为同源,Elixir以特定语法来直接调用Erlang库函数)。 本章将展示一些Elixir中没有,但是常用(常见+有用)的Erlang功能函数。

随着对Elixir更加深入的学习和使用,你可能会更多地阅读参考Erlang的 标准库手册

二进制串模块

内建的Elixir字符串模块用来处理UTF-8编码过的二进制串(binaries)。 而Erlang的二进制串模块可能对你更加有用, 因为它可以处理的二进制串不一定非要是UTF-8编码的:

  1. iex> String.to_char_list "Ø"
  2. [216]
  3. iex> :binary.bin_to_list "Ø"
  4. [195, 152]

从上面的例子你就能看出一些区别来了;String模块返回UTF-8的字符码, 而:binary是原始的数据字节。

Elixir引用Erlang的库函数十分简单。正如这个例子所示,在Erlang库模块名称前面加上冒号, 就可以直接调用Erlang的库函数了。

格式化的字符串输出

Elixir中并没有类似于C中的printf函数。作为一个可选项,你可以使用字符串插值来完成同样的功能:

  1. iex> f = Float.to_string(:math.pi, decimals: 3) |> String.rjust(10)
  2. iex> str = "Pi is approximately given by: #{f}"
  3. "Pi is approximately given by: 3.142"

另外,还可以用Erlang标准库中的:io.format/2:io_lib.format/2函数。 第一个格式化后输出到终端,而第二个输出到一个iolist。具体格式化的语法和pringf略有区别, 详见Erlang文档

  1. iex> :io.format("Pi is approximately given by:~10.3f~n", [:math.pi])
  2. Pi is approximately given by: 3.142
  3. :ok
  4. iex> to_string :io_lib.format("Pi is approximately given by:~10.3f~n", [:math.pi])
  5. "Pi is approximately given by: 3.142\n"

另外需要注意的是Erlang的格式化函数中对Unicode的处理。

日历模块

日历模块 包含本地时间和标准时间的转换函数, 以及其它一些时间函数。

  1. iex> :calendar.day_of_the_week(1980, 6, 28)
  2. 6
  3. iex> {date, time} = :calendar.now_to_local_time(:erlang.timestamp)
  4. iex> date
  5. {2016, 2, 17}
  6. iex> time
  7. {22, 4, 55}

加密模块

加密模块 包含哈希方法,数字签名, 加密等功能函数:

  1. iex> Base.encode16(:crypto.hash(:sha256, "Elixir"))
  2. "3315715A7A3AD57428298676C5AE465DADA38D951BDFAC9348A8A31E9C7401CB"

:crypto 模块不是Erlang的标准库,但是包含在了Erlang发行包中。 这要求你必须在项目的配置文件中列出:crypto模块作为依赖项。 通过修改mix.exs来加载该模块:

  1. def application do
  2. [applications: [:crypto]]
  3. end

有向图模块

有向图模块 (以及 有向图模块工具) 包含了处理有向图(有丁点和边构成)的函数。 创建了一个图实例之后,模块的算法即可帮助找寻顶点最短路径、图中的环等。

给出三个顶点,找寻从第一个到最后一个顶点的最短路径:

  1. iex> digraph = :digraph.new()
  2. iex> coords = [{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}]
  3. iex> [v0, v1, v2] = (for c <- coords, do: :digraph.add_vertex(digraph, c))
  4. iex> :digraph.add_edge(digraph, v0, v1)
  5. iex> :digraph.add_edge(digraph, v1, v2)
  6. iex> :digraph.get_short_path(digraph, v0, v2)
  7. [{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}]

ETS(Erlang Term Storage):Erlang的“Term存储”机制

模块ets以及 dets 分别处理在内存中、磁盘上存储大型数据结构。

ETS创建一个表来存储元祖。默认情况下,ETS表是受保护的:只有owner进程才能写表, 其它进程只可以读。ETS提供了一些功能,可被当做简单的数据库、键值存储或cache机制使用。

作为副作用,ets模块中的函数会修改表的状态。

  1. iex> table = :ets.new(:ets_test, [])
  2. # Store as tuples with {name, population}
  3. iex> :ets.insert(table, {"China", 1_374_000_000})
  4. iex> :ets.insert(table, {"India", 1_284_000_000})
  5. iex> :ets.insert(table, {"USA", 322_000_000})
  6. iex> :ets.i(table)
  7. <1 > {"USA", 322000000}
  8. <2 > {"China", 1_374_000_000}
  9. <3 > {"India", 1_284_000_000}

数学模块

数学模块 包含了常用数学操作, 如三角函数、指数或底数函数等等。

  1. iex> angle_45_deg = :math.pi() * 45.0 / 180.0
  2. iex> :math.sin(angle_45_deg)
  3. 0.7071067811865475
  4. iex> :math.exp(55.0)
  5. 7.694785265142018e23
  6. iex> :math.log(7.694785265142018e23)
  7. 55.0

队列(queue)模块

队列 queue 是一种数据结构 实现了双向先进先出的高效率队列:

  1. iex> q = :queue.new
  2. iex> q = :queue.in("A", q)
  3. iex> q = :queue.in("B", q)
  4. iex> {value, q} = :queue.out(q)
  5. iex> value
  6. {:value, "A"}
  7. iex> {value, q} = :queue.out(q)
  8. iex> value
  9. {:value, "B"}
  10. iex> {value, q} = :queue.out(q)
  11. iex> value
  12. :empty

随机值(rand)模块

rand模块函数 可以返回随机值或是设置随机seed:

  1. iex> :rand.uniform()
  2. 0.8175669086010815
  3. iex> _ = :rand.seed(:exs1024, {123, 123534, 345345})
  4. iex> :rand.uniform()
  5. 0.5820506340260994
  6. iex> :rand.uniform(6)
  7. 6

zip和zlib模块

zip模块 可以让你读写磁盘或内存中的zip文件, 以及提取其文件信息等。

以下代码计算了zip压缩包中的文件数量:

  1. iex> :zip.foldl(fn _, _, _, acc -> acc + 1 end, 0, :binary.bin_to_list("file.zip"))
  2. {:ok, 633}

zlib模块 处理zlib格式的数据压缩 (如gzip中用的):

  1. iex> song = "
  2. ...> Mary had a little lamb,
  3. ...> His fleece was white as snow,
  4. ...> And everywhere that Mary went,
  5. ...> The lamb was sure to go."
  6. iex> compressed = :zlib.compress(song)
  7. iex> byte_size song
  8. 110
  9. iex> byte_size compressed
  10. 99
  11. iex> :zlib.uncompress(compressed)
  12. "\nMary had a little lamb,\nHis fleece was white as snow,\nAnd everywhere that Mary went,\nThe lamb was sure to go."