技術メモ

プログラミングとか電子工作とか

Elixir入門(第十三章 alias, require, and import)

f:id:ysmn_deus:20190122112104p:plain

どうも、靖宗です。
今回は名前からするに外部ファイルの使い方とか名前空間とか?

# Alias the module so it can be called as Bar instead of Foo.Bar
alias Foo.Bar, as: Bar

# Require the module in order to use its macros
require Foo

# Import functions from Foo so they can be called without the `Foo.` prefix
import Foo

# Invokes the custom code defined in Foo as an extension point
use Foo

順に追っていきましょう。

alias

これはなんとなく分かりやすいと思いますが、宣言したスコープ下でas:以下として使用するって感じでしょうか。

defmodule Stats do
  alias Math.List, as: List
  # In the remaining module definition List expands to Math.List.
end

このように利用すると、Statsモジュールの内部でListはMath.Listをさすように変えられます。
一応元々のListもElixir.Listとして生きているようです。
おそらくグローバルで使える関数とかモジュールとかはElixir.で利用できそう。
ショートカット(文字数を少なくする)としても使用されるようです。

また、alias Math.Listと書けばalias Math.List, as: Listと認識されるようです。冗長じゃなくて良い感じ。
スコープは定義したブロック下のみ。

defmodule Math do
  def plus(a, b) do
    alias Math.List
    # ...
  end

  def minus(a, b) do
    # ...
  end
end

ここではMath.plusの中だけです。

require

Elixirでのmacroメタプログラミング(コードを書くためのコード)用の機能だそうです。Cでいうdefineとかそのへん?
マクロはコンパイル時に展開されるようです。 とりあえずサンプルを見てみます。

iex> Integer.is_odd(3)
** (UndefinedFunctionError) function Integer.is_odd/1 is undefined or private. However there is a macro with the same name and arity. Be sure to require Integer if you intend to invoke this macro
iex> require Integer
Integer
iex> Integer.is_odd(3)
true

ElixirではIntegerというマクロが用意されていて、使用するときにはrequire Integerが必要なようです。
デフォルトで用意されてないのは実行を少しでも早くする工夫なんでしょうか?
他のMacroの章で詳しく書かれてるみたいなんでとりあえずスルーします。

import

同じモジュールの関数を何回も使用する時など、関数名だけで実行したいときとかに使うっぽい。

iex> import List, only: [duplicate: 2]
List
iex> duplicate :ok, 3
[:ok, :ok, :ok]

この例ではList.duplicate/2をimportしている。
:onlyで指定の関数だけを、:exceptで指定の関数以外をインポートできるようです。

また、:onlyを用いてmacroやfunctionをインポートすることもできるようで。

import Integer, only: :macros
import Integer, only: :functions

ますますmacroがなんなのか分からなくなってきた・・・
先に見た方がいいのかなぁ。
ちなみに、上の例でIntegerを使っているのでrequireが必要っぽいが、importはその辺は勝手にrequireしてくれる模様。
そしてこのimportもスコープは宣言したブロックでのみ有効。

use

ぶっちゃけなんのこっちゃ分かりません。
テストのこと書いてるんでテストの時にでも見直します。
一応

defmodule Example do
  use Feature, option: :value
end

と書くと

defmodule Example do
  require Feature
  Feature.__using__(option: :value)
end

と展開されるマクロ、という事だそうです。

Understanding Aliases

Elixir内で表記されているエイリアス(StringとかKeyword)とかは、実はアトムだそうです。

iex> is_atom(String)
true
iex> to_string(String)
"Elixir.String"
iex> :"Elixir.String" == String
true

エイリアスがアトムに展開されている理由はErlangVMで動いてることに起因してるんだとか。
Erlangを知ってる人ならなるほどなっとくなのかな。

Module nesting

モジュールのネストの話。
一応モジュールはネスとしてかけるそうです。
大きくなりすぎたら管理しづらいからかな。

defmodule Foo do
  defmodule Bar do
  end
end

Stringが実際はElixir.Stringである様に、モジュールも実際はElixir.Fooとかになっているはず。
実際は下記のようになっているそうで。

defmodule Elixir.Foo do
  defmodule Elixir.Foo.Bar do
  end
  alias Elixir.Foo.Bar, as: Bar
end

あまり気にしなくても良さそう?

Multi alias/import/require/use

Elixirのv1.2からは、さっきまで紹介してきたalias``import``require``useをネストしたモジュールで一気に取り込む方法があるそうです。

alias MyApp.{Foo, Bar, Baz}

なるほど。
使うときになったらまた思い出せばいいかな。