Elixir Schoolの学習メモです。
モジュールと名前つき関数
defmodule Example do # <- モジュール
def greeting(name) do # <- 名前付き関数
"Hello #{name}."
end
end
Example.greeting "Sean"
"Hello Sean."
モジュールは関数群を名前空間へと組織する最良の方法です。
関数をまとめることに加えて、関数のレッスンで取り上げた名前付き関数やプライベート関数を定義できます。
※名前空間(namespace)とは、名前の集合全体を小さな空間に区切り、それぞれに異なる識別名を与えることで、その空間内では他の空間に含まれる名前の競合・衝突を意識しなくて良いようにしたものです。
プログラミング言語だと頻出する概念で、名前付き関数をモジュールにまとめて構造化できる、と捉えてもらうといいかも。
モジュールの属性
Elixirモジュールはそれぞれ対応するメタデータを持っている。メタデータの各項目のことをモジュールの属性といい、名前によって識別される。
モジュールの内部では、@記号を名前の前につけて属性につけて、属性にアクセスすることができる。
defmodule Example do
@greeting "Hello"
def greeting(name) do
~s(#{@greeting} #{name}.)
end
end
Elixirで予約されている属性があり、一般的なのは以下の3つ。
moduledoc
… 現在のモジュールにドキュメントをつける。
doc
… 関数やマクロについてのドキュメント管理。
behaiviour
… OTPまたはユーザが定義した振る舞い(ビヘイビア)に用いる。
構造体
構造体は、定義済みのキーの一群とデフォルト値を持つ特殊なマップをラップしたモジュール。
構造体を定義するにはdefstruct
を用い、フィールドとデフォルト値のキーワードリストを添える。
defmodule Subscriber do
defstruct name: "", paid: false, over_18: true
end
iex(2)> s1 = %Subscriber{}
%Subscriber{name: "", over_18: true, paid: false}
iex(3)> s2 = %Subscriber{ name: "Dave" }
%Subscriber{name: "Dave", over_18: true, paid: false}
構造体のフィールドへのアクセス
iex(4)> s2.name
"Dave"
構造体の更新
iex(7)> s2 = %Subscriber{ s2 | name: "Tom" }
%Subscriber{name: "Tom", over_18: true, paid: false}
iex(8)> s2
%Subscriber{name: "Tom", over_18: true, paid: false}
構造体はマップに対してマッチすることができる。
iex(11)> %{name: "Tom"} = s2
%Subscriber{name: "Tom", over_18: true, paid: false}
Elixir 1.8以降、構造体にカスタムイントロスペクション機能が追加された。
iex(12)> inspect(s2)
"%Subscriber{name: \"Tom\", over_18: true, paid: false}"
@deriveで出力対象を指定できる。
defmodule Subscriber do
@derive {Inspect, only: [:name]}
# もしくはexceptで定義できる
# @derive {Inspect, except: [:paid, :over_18]}
defstruct name: "", paid: false, over_18: true
end
iex(15)> inspect(s2)
"#Subscriber<name: \"Tom\", ...>"
モジュールや構造体の取り扱いを簡単にするディレクティブ
- aliasディレクティブ
- importディレクティブ
- requireディレクティブ
- useマクロ
alias
モジュール名をエイリアスすることができる。
import
関数を取り込みたい場合に使う。
require
モジュールで定義したマクロを使うときは、そのモジュールをrequireする。
コードをコンパイルするときに、マクロ定義が有効になっていることが保証される。
use
他のモジュールを利用して現在のモジュールの定義を変更することができる。