use Module
除了在Module
上调用__using__
宏外, 不作其余任何事情. import Module
会把Module
模块的全部非私有函数和宏引入到当前模块中, 能够直接经过名字调用函数和宏. require Module
容许使用一个模块的宏, 但并不导入他们. 必须经过全名(带名称空间)来引用.shell
例如:函数
defmodule User do defmacro __using__(_opts) do IO.puts "use User" end def get_username() do "developerworks" end end
defmodule Hello do use User def hi() do IO.puts "Hello, #{get_username()}" # User模块未被导入,该函数不存在 end end
再来看下面的例子:测试
defmodule User do defmacro __using__(_opts) do quote do import User end end def get_username() do "developerworks" end end defmodule ModB do use User def hi() do IO.puts "Hello, #{get_username()}" # User模块已导入, 该函数存在 end end
当你使用use User
的时候, 它生产了一个import
语句, 把User
的函数和宏插入到Hello
中.ui
下面是一个实际的例子, 一个Zlib模块用于压缩和解压数据, 代码能够保存为zlib.exs
脚本文件方便测试code
defmodule Zlib do @moduledoc """ Zlib compress and decompress functions """ @doc """ use Zlib """ defmacro __using__(_opts) do quote do import Zlib end end def compress(data) do z = :zlib.open() :zlib.deflateInit(z) :zlib.deflate(z, data) result = :zlib.deflate(z, << >>, :finish) :zlib.deflateEnd(z) :erlang.list_to_binary(result) end def decompress(data, wbits \\ 15) do z = :zlib.open() :zlib.inflateInit(z, wbits) [result|_] = :zlib.inflate(z, data) :zlib.inflateEnd(z) result end end require Logger use Zlib compressed_data = Zlib.compress("test") Logger.info "#{inspect compressed_data}" decompressed_data = Zlib.decompress(compressed_data) Logger.info "#{decompressed_data}"
上面的代码实际上运行的时候回出错, 经过个人测试use Zlib
只能用在模块内部. 不能直接在全局空间中使用, 正确的调用代码以下:作用域
defmodule Test do @moduledoc """ 压缩和解压缩测试模块. """ def run() do require Logger # 把Zlib模块中的函数和宏导入到当前模块的做用域中. use Zlib compressed_data = compress("test") Logger.info "#{inspect compressed_data}" decompressed_data = decompress(compressed_data) Logger.info "#{decompressed_data}" end end Test.run
经过上述实验, 咱们在模块Zlib中定义了一个 __using__
宏, 正如文章最开始所述, use Zlib
惟一的做用就是调用目标模块Zlib
中的__using__
宏, 在__using__
宏中咱们import
了自身, 也就是导入了Zlib
模块中的全部公共(定义为def
而非defp
)的函数和宏.get
能够实验一下, 若是你在Zlib
模块中增长一个私有函数(private_test
), 那么咱们use Zlib
后在模块外部调用private_test
是会发生以下错误的.it
zlib.exs:33: warning: function private_test/0 is unused ** (CompileError) zlib.exs:53: undefined function private_test/0 (stdlib) lists.erl:1337: :lists.foreach/2 zlib.exs:41: (file) (elixir) lib/code.ex:363: Code.require_file/2
另外对于import
, 还有only
, except
选项, 分别表示只导入指定的函数, 以及排除指定的函数, 例如:io
import Zlib, only: compress import Zlib, except: decompress
有的模块中包含多个同名, 参数数(arity)不一样的函数, 你甚至能够按函数的参数个数来指定要导入的特定函数, 好比, 在Elixir内置的模块List
中存在List.to_integer/1
和List.to_integer/2
两个名为to_integer
的函数, 若是你只想导入to_integer/1
,那么能够按下面的方式来导入:编译
import List, only: [to_integer: 1]
这里与上面的区别在于only
接受的是一个列表, 也就是说, 你还能够导入其余你须要指定的函数, 好比下面的代码仅导入了to_integer/1
和duplicate/2
两个List
模块中的函数.
import List, only: [to_integer: 1, duplicate: 2]
最后的require
比较简单, 其做用相似于C语言中的#include "zlib.h"
把头文件包含进来, 编译连接的时候就会去查找对应的共享库. require
的做用与之相似,要使用其余模块所提供的函数和宏, 就必需要require
进来.