为了方便软件重用,Elixir提供了三个指令alias
、require
和import
,以及use
宏。
alias
alias
可以让我们通过别名去访问模块
defmodule Sayings.Greetings do
def basic(name), do: "Hi, #{name}"
end
defmodule Example do
alias Sayings.Greetings
def greeting(name), do: Greetings.basic(name)
end
# Without alias
defmodule Example do
def greeting(name), do: Sayings.Greetings.basic(name)
end
如果别名有冲突,或者我们想给模块命一个不同的名字时,可以使用:as
参数
defmodule Example do
alias Sayings.Greetings, as: Hi
def print_message(name), do: Hi.basic(name)
end
也可以指定多个别名:
defmodule Example do
alias Sayings.{Greetings, Farewells}
end
import
每当我们想访问其他模块中的函数或宏而不使用完全限定的名称时,我们都会使用import
请注意,我们只能导入公共函数,因为从外部无法访问私有函数。
# 只导入 List 模块的 duplicate/2 函数
iex> import List, only: [duplicate: 2]
List
iex> duplicate :ok, 3
[:ok, :ok, :ok]
默认情况下,import
会导入模块中的所有函数和宏,我们可以通过:only
(只导入该函数)和:except
(除了该函数)来进行过滤
# 只导入last/1函数
import List, only: [last: 1]
# 导入除了last/1函数的其他函数
import List, except: [last: 1]
# 只导入函数
import List, only: :functions
# 只导入宏
import List, only: :macros
require
require
调用其他模块的宏,与import
的区别是require
对宏有效而对函数无效
defmodule Example do
require SuperMacros
SuperMacros.do_stuff
end
alias
、require
和import
都支持词法范围。对于下面的代码,Math.List
只作用于plus
defmodule Math do
def plus(a, b) do
alias Math.List
# ...
end
def minus(a, b) do
# ...
end
end
use
use
宏经常用作扩展点。允许另一个模块在当前模块注入任何代码。
defmodule AssertionTest do
use ExUnit.Case, async: true
test "always pass" do
assert true
end
end
原理
use
的原理是,当我们在当前模块中调用use
时,Elixir会执行指定模块中所定义的__using__
回调。回调执行的结果会成为当前模块定义的一部分。
defmodule Hello do
defmacro __using__(_opts) do
quote do
def hello(name), do: "Hi, #{name}"
end
end
end
这里我们在Hello
模块中定义了__using__
回调,回调中定义了一个名为hello/1
的函数。 接着,我们创建一个新模块来使用上面的代码:
defmodule Example do
use Hello
end
在 IEx 中,我们可以看到hello/1
这个函数是存在我们的Example
模块中的:
using/1回调参数用法
defmodule Hello do
defmacro __using__(opts) do
greeting = Keyword.get(opts, :greeting, "Hi")
quote do
def hello(name), do: unquote(greeting) <> ", " <> name
end
end
end
defmodule Example do
use Hello, greeting: "Hola"
end
iex> Example.hello("Sean")
"Hola, Sean"
其他
对于alias/import/require/use
,都支持对多个模块的导入
alias MyApp.{Foo, Bar, Baz}