17
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ElixirAdvent Calendar 2022

Day 10

Elixir 構造体(struct)からモジュール名を取得したい

Last updated at Posted at 2022-11-16

Elixir構造体(struct)からモジュール名を取得する方法をまとめます。

簡単そうに見えてしっかり勉強しないとややこしい部分があります。

論よりRUN

早速IExを開きます。

iex

Time.utc_now/1を実行すると現在の時刻がTime構造体で帰ってきます。

%Time{} = Time.utc_now()

構造体からモジュール名を取得する方法

構造体からモジュール名を取得する方法はいくつかあります。

詳しくは公式ドキュメントのKernel.SpecialForms.%struct{}ページで解説されています。

:__struct__キーの値と取得

time = Time.utc_now()
time |> is_struct()
time.__struct__

ここで注意が必要なのはMapとは異なり、Accessが実装されていないのでdata[key]シンタックスは使えません。

iex> Time.utc_now()[:__struct__]
** (UndefinedFunctionError) function Time.fetch/2 is undefined (Time does not implement the Access behaviour. If you are using get_in/put_in/update_in, you can specify the field to be accessed using Access.key!/1)
    (elixir 1.14.2) Time.fetch(~T[23:52:17.032092], :__struct__)
    (elixir 1.14.2) lib/access.ex:288: Access.get/3
    iex:33: (file)

:__struct__キーに対してパターンマッチ

%{__struct__: mod} = Time.utc_now()
mod

構造体名に対してパターンマッチ

%mod{} = Time.utc_now()
mod

この特性は(構造体の名前が不要でも)ある値が構造体であることを確認する目的に利用できます。

%_{} = Time.utc_now()

structという名の関数たち

余談ですが、structという名の関数がいくつか存在します。知らないと混乱するかもしれません。

__struct__/1

詳しくは公式ドキュメントのKernel.defstruct/1ページで解説されています。

Time.__struct__(
  calendar: Calendar.ISO,
  hour: 0,
  microsecond: {0, 0},
  minute: 0,
  second: 0
)

結果は普通に構造体を生成する場合と同じです。

%Time{
  calendar: Calendar.ISO,
  hour: 0,
  microsecond: {0, 0},
  minute: 0,
  second: 0
}

こういうヘンテコなコードも成り立ってしまいます。

Time.utc_now.__struct__.__struct__(
  calendar: Calendar.ISO,
  hour: 0,
  microsecond: {0, 0},
  minute: 0,
  second: 0
)

Kernel.struct!/2

  • 構造体を作成、更新する関数
struct!(Time, %{
  calendar: Calendar.ISO,
  hour: 0,
  microsecond: {0, 0},
  minute: 0,
  second: 0
})
time = Time.utc_now
struct!(time, %{ microsecond: {0, 0} })

プロトコル

通常、構造体のモジュール名を取得することはあまりないと思います。:__struct__キーはElixir言語にサポートされているので、使いたければ使って問題ないそうです。公式ドキュメントのKernel.SpecialForms.%struct{}のページで解説されています。

頻繁に構造体のモジュール名が必要となる場合、データと振る舞いがパッケージ化されたオブジェクト指向プログラミング的な構造になっている可能性があり、その場合はプロトコルを実装するとスッキリする場合あると以前聞いたことがあります。知らんけど。

ご参考までに

17
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?