- Mapの拡張してStructがある。
- Structは初期値の設定とコンパイル時のチェックを行ってくれる
Defining structs
defmodule User do
# フィールド名と初期値を定義する
defstruct name: "John", age: 27
end
# mapに似てるけど % モジュール名 {} で作成できる
iex> %User{}
%User{age: 27, name: "John"}
# 初期値を与えればデフォルト値は上書かれる
iex> %User{name: "Meg"}
%User{age: 27, name: "Meg"}
# 存在しないフィールドを指定すると例外となる
iex> %User{oops: :field}
** (CompileError) iex:3: unknown key :oops for struct User
Accessing and updating structs
- Mapと同じようにStructのフィールドにアクセスしたり更新したりできる
- 同様にパターンマッチも使える
# Userを初期値の状態でjohnとして束縛
iex> john = %User{}
%User{age: 27, name: "John"}
# フィールドには . でアクセスできる
iex> john.name
"John"
# 更新はmap と ほとんど同じように更新できる
# Mapと同じくimmutableな存在なので更新後の値をvariableに束縛しないと後で使えない
iex> meg = %{john | name: "Meg"}
%User{age: 27, name: "Meg"}
# 存在しないフィールドを更新しようとするとエラーになる
iex> %{meg | oops: :field}
** (ArgumentError) argument error
# パターンマッチを使ってnameフィールドの値を取得している
iex> %User{name: name} = john
%User{age: 27, name: "John"}
iex> name
"John"
# マッチしなければエラー
iex> %User{name: "Meg"} = john
** (MatchError) no match of right hand side value: %User{age: 27, name: "John"}
Structs are just bare maps underneath
- StructはMapとしてみた場合、struct という特別なフィールドを持っている
- MapのプロトコルやEnum、DictなどのモジュールではStructをargumentにできない。
- Mapモジュールのargumentにはできる。
# is_mapはtrueが返る
iex> is_map(john)
true
# johnの__struct__フィールドを見るとUserが返る
iex> john.__struct__
User
# Mapモジュールは使える
iex> Map.keys(john)
[:__struct__, :age, :name]