もやもやエンジニア

IT系のネタで思ったことや技術系のネタを備忘録的に綴っていきます。フロント率高め。

Elixir 入門 その14 - Structs

  • Mapの拡張してStructがある。
  • Structは初期値の設定とコンパイル時のチェックを行ってくれる

Defining structs

  • defstruct でStructを定義できる
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]