首页
Elixir alias, require 和 import

为了方便软件重用,Elixir提供了三个指令aliasrequireimport,以及use宏。

alias

示例代码: demo5.ex

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

示例代码: demo6.ex

每当我们想访问其他模块中的函数或宏而不使用完全限定的名称时,我们都会使用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

aliasrequireimport都支持词法范围。对于下面的代码,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}