Elixir入門 13: aliasとrequireおよびimport
Tags: elixir, webdev, tutorial, programming
Published: 2018-12-11 01:33:13

---
title: Elixir入門 13: aliasとrequireおよびimport
published: true
description: Elixir公式サイトの許諾を得て「alias, require, and import」の解説にもとづき、加筆補正を加えて、Elixirのディレクティブaliasとrequireおよびimportの使い方についてご説明します。
tags: #elixir, #webdev, #tutorial, #programming
---

本稿はElixir公式サイトの許諾を得て「[alias, require, and import](https://elixir-lang.org/getting-started/alias-require-and-import.html)」の解説にもとづき、加筆補正を加えて、Elixirのディレクティブ`alias`と`require`および`import`の使い方についてご説明します。

ソフトウェアが再利用しやすいように、Elixirはつぎの3つのディレクティブとひとつのマクロを備えています。ディレクティブは[レキシカルスコープ](https://ja.wikipedia.org/wiki/%E9%9D%99%E7%9A%84%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97)(lexical scope)をもちます。`use`は標準のマクロです。

- `alias`ディレクティブ: モジュールが別名で呼び出せるように別名を与えます。
- `require`ディレクティブ: マクロが呼び出せるようにモジュールを要求します。
- `import`ディレクティブ: モジュール名なしに関数が呼び出せるようにモジュールを読み込みます。
- `use`マクロ: モジュール内のコードを拡張ポイントとして呼び出します。


# alias
[`alias/2`ディレクティブ](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#alias/2)は、すでにあるモジュールに任意の別名を与えます。つぎのエイリアスが使われていないコードを例にとりましょう。

```elixir
defmodule Sayings.Greetings do
  def basic(name), do: "hello, #{name}"
end

defmodule Example do
  def greeting(name), do: Sayings.Greetings.basic(name)
end
```

```elixir
iex> Example.greeting("world")
"hello, world"
```

第2引数を省くと、ドット(`.`)で区切られたモジュール名の最後の識別子がエイリアスになります。

```elixir
defmodule Example do
  alias Sayings.Greetings
  def greeting(name), do: Greetings.basic(name)
end
```

第2引数で与える名前には、`as:`オプションを添えてください。エイリアス名は大文字ではじめなければなりません。

```elixir
defmodule Example do
  alias Sayings.Greetings, as: Hi
  def greeting(name), do: Hi.basic(name)
end
```

Elixirのモジュールはすべて名前空間`Elixir`に定められます。デフォルトではそれが省けるということです。

```elixir
iex> alias Example, as: String
Example
iex> String.greeting("tokyo")
"hello, tokyo"
iex> Elixir.String.length("hello")
5
```

エイリアスはレキシカルスコープをもちます。モジュールで定めれば、モジュール内の関数すべてがそのエイリアスを参照できます。

```elixir
defmodule Example do
  alias Sayings.Greetings, as: Hi
  def greeting(name), do: Hi.basic(name)
  def greeting_ex(name), do: Hi.basic(name) <> "!!"
end
```

```elixir
iex> Example.greeting_ex("world")
"hello, world!!"
```

エイリアスを関数の中で定めると、他の関数からは参照できません。

```elixir
defmodule Example do
  def greeting(name) do
    alias Sayings.Greetings, as: Hi
    Hi.basic(name)
  end
  def greeting_ex(name), do: Hi.basic(name) <> "!!"
end
```

```elixir
iex> Example.greeting("world")
"hello, world"
iex> Example.greeting_ex("world")
** (UndefinedFunctionError) function Hi.basic/1 is undefined (module Hi is not available)
    Hi.basic("world")
    example.exs: Example.greeting_ex/1
```


# require
Elixirには、メタプログラミングの仕組みとしてマクロが備わっています。メタプログラミングとは、コードが生成されるコードを書くことです。マクロはコンパイルのとき展開されます。

パブリックの関数はグローバルに用いることができます。けれど、マクロを使うには、それが定義されたモジュールを[`require/2`ディレクティブ](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#require/2)でオプトインしなければなりません。

`Integer.is_odd/1`はモジュールにマクロとして定められています(図001)。そのため、あらかじめ`Integer`モジュールを`require/2`で設定しなければ使えません。

#### 図001■リファレンスのInteger.is_odd/1の項にmacroの表示
![elixir_13_001.png](https://thepracticaldev.s3.amazonaws.com/i/eanedky9c8y072id1l1y.png)

```elixir
iex> Integer.is_odd(5)
** (CompileError) iex: you must require Integer before invoking the macro Integer.is_odd/1
    (elixir) src/elixir_dispatch.erl:97: :elixir_dispatch.dispatch_require/6
iex> require Integer
Integer
iex> Integer.is_odd(5)
true
```

- [`Integer.is_even/1`](https://hexdocs.pm/elixir/Integer.html#is_even/1): 奇数かどうかを論理値で返します。
- [`Integer.is_odd/1`](https://hexdocs.pm/elixir/Integer.html#is_odd/1): 偶数かどうかを論理値で返します。

ディレクティブ`alias/2`と同じく、`require/2`もレキシカルスコープをもちます。

# import

[`import/2`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#import/2)は、完全修飾名を使わずに関数やマクロが参照できるディレクティブです。モジュール名なしに関数やマクロが呼び出せるようになります。

```elixir
iex> import List
List
iex> first([1, 2, 3])
1
iex> last([1, 2, 3])
3
iex> flatten([1, [[2], 3]])
[1, 2, 3]
```

- [`List.first/1`](https://hexdocs.pm/elixir/List.html#first/1): リストの最初の要素を返します。
- [`List.last/1`](https://hexdocs.pm/elixir/List.html#last/1): リストの最後の要素を返します。

第2引数に`only:`オプションで、読み込む関数やマクロを絞り込めます。

```elixir
iex> import List, only: [first: 1, last: 1]
List
iex> first([1, 2, 3])
1
iex> flatten([1, [[2], 3]])
** (CompileError) iex:9: undefined function flatten/1
```

第2引数のオプションには関数・マクロのリストのほか、`:macros`と`:functions`が与えられます。なお、`import/2`で読み込まれるマクロは、内部的に`require/2`も行わるのです。

```elixir
iex> import Integer, only: :macros
Integer
iex> is_even(4)
true
iex> digits(123)
** (CompileError) iex: undefined function digits/1
iex> Integer.digits(123)
[1, 2, 3]
```

```elixir
iex> import Integer, only: :functions
Integer
iex> digits(123)
[1, 2, 3]
iex> is_odd(3)
** (CompileError) iex: undefined function is_odd/1
```

第2引数のオプションとして、`only:`の替わりに`except:`で逆に読み込みから除くリストも定められます。

```elixir
iex> import List, except: [first: 1, last: 1]
List
iex> flatten([1, [[2], 3]])
[1, 2, 3]
iex> last([1, 2, 3])
** (CompileError) iex: undefined function last/1
```

`import/2`ディレクティブもレキシカルスコープです。関数の中に定めると、他の関数からは参照できず、コンパイルエラーになります。

```elixir
defmodule Example do
  def split(number) do
    import Integer, only: [digits: 1]
    digits(number)
  end
  def test(name), do: digits(name)  #コンパイルエラー
end
```


# use
[`use/2`マクロ](https://hexdocs.pm/elixir/Kernel.html#use/2)を使うと、モジュールの定めを他のモジュールから変えられるようになります。`use/2`が呼び出すのは、モジュールに加えられた`__using__/1`コールバックのマクロです。すると、このマクロの働きを別のモジュールに取り込めます。

つぎのコードが`__using__/1`コールバックを定めたモジュールの例です。ここではテスト用に使うだけですので、マクロについて詳しくは「[Macros](https://elixir-lang.org/getting-started/meta/macros.html)」をお読みください。

```elixir
defmodule Hello do
  defmacro __using__(_opts) do
    quote do
      def greeting(name), do: "hello, #{name}"
    end
  end
end
```

別のモジュールで`use/2`を用いると、`__using__/1`コールバックに定めた関数が、そのモジュールから呼び出せます。

```elixir
defmodule Example do
  use Hello
end
```

```elixir
iex> Example.greeting("world")
"hello, world"
```

`use/2`の機能は、つぎのように`require/2`を使ったのと同じです。

```elixir
defmodule Example do
  # use Hello
  require Hello
  Hello.__using__(greeting: :value)
end
```

さらに、`__using__/1`コールバックをつぎのように書き替えます。すると、関数の処理が、`use/2`の第2引数により変えられるのです。

```elixir
defmodule Hello do
  defmacro __using__(opts) do
    hello = Keyword.get(opts, :hello, "hello")
    quote do
      def greeting(name), do: unquote(hello) <> "," <> name
    end
  end
end

defmodule Example do
  use Hello, hello: "こんにちは"
end
```

```elixir
iex> Example.greeting("日本")
"こんにちは,日本"
```


# エイリアスを理解する
Elixirのエイリアスは、コンパイルするときアトムに変換される頭が大文字の識別子(`String`や`Keyword`など)です。

```elixir
iex> is_atom(String)
true
iex> to_string(String)
"Elixir.String"
iex> String == :"Elixir.String"
true
```

`alias/2`を用いると、エイリアスはアトムに展開されます。Erlang VM(およびElixir)では、モジュールはアトムで表されるからです。

```elixir
iex> :lists.flatten([1, [[2], 3]])
[1, 2, 3]
```


# モジュールを入れ子にする
モジュールは入れ子にすることができます。外から子のモジュールを参照するには、親からの完全修飾名を用いなければなりません。

```elixir
defmodule Example do
  def greeting(name), do: "hello, #{name}"
  defmodule Greetings do
    def morning(name), do: "good morning, #{name}"
  end
end
```

```elixir
iex> Example.greeting("world")
"hello, world"
iex> Example.Greetings.morning("tokyo")
"good morning, tokyo"
```

親モジュールの中に子のモジュールが定められたあとであれば、子は完全修飾名を使わずに参照できます。子モジュールが親のレキシカルスコープに含まれるため、内部的にエイリアスがつくられるからです。

```elixir
defmodule Example do
  def greeting(name), do: "hello, #{name}"
  defmodule Greetings do
    def morning(name), do: "good morning, #{name}"
  end
  # alias Example.Greetings  #<- 内部的にエイリアスがつくられる
  def call_child(name), do: Greetings.morning(name)
end
```

```elixir
iex> Example.call_child("japan")
"good morning, japan"
```

完全修飾名を用いれば、子モジュールは親の外でも定められます。このとき、子モジュールは必ずしも親のあとに書かなくても構いません。このとき親モジュールが子の名前だけで参照したいときには、エイリアスを使ってください。

```elixir
defmodule Example do
  def greeting(name), do: "hello, #{name}"
end

defmodule Example.Greetings do
  def morning(name), do: "good morning, #{name}"
end
```

さらに、完全修飾名さえ使えば、親モジュールがなくても子モジュールは定められます。すべてのモジュール名はアトムに変換されるためです。

```elixir
defmodule Example.Greetings.Japan do
  def greeting(name), do: "こんにちは, #{name}"
end
```

```elixir
iex> Example.Greetings.Japan.greeting("日本")
"こんにちは, 日本"
```


# alias/import/require/useを複数使う
`alias`や`import`、`require`、`use`は一度に複数のモジュールを定めることができます。つぎのコードは、ふたつの子モジュールにモジュール名のエイリアスを与える例です。

```elixir
iex> alias Example.Greetings.{US, Japan}
[Example.Greetings.US, Example.Greetings.Japan]
```


#### Elixir入門もくじ
- [Elixir入門 01: コードを書いて試してみる](https://dev.to/gumi/elixir-01--2585)
- [Elixir入門 02: 型の基本](https://dev.to/gumi/elixir-02--30n1)
- [Elixir入門 03: 演算子の基本](https://dev.to/gumi/elixir-03--33im)
- [Elixir入門 04: パターンマッチング](https://dev.to/gumi/elixir-04--1346)
- [Elixir入門 05: 条件 - case/cond/if](https://dev.to/gumi/elixir-05----casecondif-60o)
- [Elixir入門 06: バイナリと文字列および文字リスト](https://dev.to/gumi/elixir-06--35na)
- [Elixir入門 07: キーワードリストとマップ](https://dev.to/gumi/elixir-07--39hi)
- [Elixir入門 08: モジュールと関数](https://dev.to/gumi/elixir-08--1c4c)
- [Elixir入門 09: 再帰](https://dev.to/gumi/elixir-09--1a0p)
- [Elixir入門 10: EnumとStream](https://dev.to/gumi/elixir-10-enumstream-4fpb)
- [Elixir入門 11: プロセス](https://dev.to/gumi/elixir-11--2mia)
- [Elixir入門 12: 入出力とファイルシステム](https://dev.to/gumi/elixir-12--4og6)
- Elixir入門 13: aliasとrequireおよびimport
- [Elixir入門 14: モジュールの属性](https://dev.to/gumi/elixir-14--3511)
- [Elixir入門 15: 構造体](https://dev.to/gumi/elixir-15--4f43)
- [Elixir入門 16: プロトコル](https://dev.to/gumi/elixir-16--lif)
- [Elixir入門 17: 内包表記](https://dev.to/gumi/elixir-17--5gci)
- [Elixir入門 18: シギル](https://dev.to/gumi/elixir-18--5791)
- [Elixir入門 19: tryとcatchおよびrescue](https://dev.to/gumi/elixir-19-trycatchrescue-50i8)
- [Elixir入門 20: 型の仕様とビヘイビア](https://dev.to/gumi/elixir-20--j50)
- [Elixir入門 21: デバッグ](https://dev.to/gumi/elixir-21--21a1)
- [Elixir入門 22: Erlangライブラリ](https://dev.to/gumi/elixir-22-erlang-2492)
- [Elixir入門 23: つぎのステップ](https://dev.to/gumi/elixir-23--50ik)

##### 番外
- [Elixir入門: Plugを使うには](https://dev.to/gumi/elixir-plug-40lb)