概要
Elixirで構造体のプロパティを共通化したかったので、メモも兼ねて共有します。
環境
$ elixir -v
Erlang/OTP 22 [erts-10.7.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
Elixir 1.10.3 (compiled with Erlang/OTP 22)
コード
common_struct.ex
# 共通プロパティを持ち、`use`によって構造体を定義するモジュール
defmodule CommonStruct do
defmacro __using__(attributes) do
quote do
# 共通プロパティ
common_attributes = [str: "", int: 0]
# 引数のキーワードリストと一緒に`defstruct`へ渡し、呼び出しモジュールの構造体として定義する。
common_attributes ++ unquote(attributes) |> defstruct
end
end
end
my_struct.ex
defmodule MyStruct do
# 独自に定義するプロパティとデフォルト値をキーワードリストにして渡す。
use CommonStruct, bool: false, float: 0.1
end
iex
iex(1)> i %MyStruct{}
Term
# ちゃんと定義できてます!
%MyStruct{bool: false, float: 0.1, int: 0, str: ""}
Data type
MyStruct
Description
This is a struct. Structs are maps with a __struct__ key.
Reference modules
MyStruct, Map
Implemented protocols
IEx.Info, Inspect
# デフォルト値
iex(2)> %MyStruct{}
%MyStruct{bool: false, float: 0.1, int: 0, str: ""}
# 初期値あり
iex(3)> %MyStruct{bool: true, float: 3.14, int: 100, str: "hoge"}
%MyStruct{bool: true, float: 3.14, int: 100, str: "hoge"}
CommonStruct
には構造体が定義されていないので、上のコードでは%CommonStruct{}
を実行するとエラーが発生します。
iex
iex(4)> %CommonStruct{}
** (CompileError) iex:4: CommonStruct.__struct__/1 is undefined, cannot expand struct CommonStruct. Make sure the struct name is correct. If the struct name exists and is correct but it still cannot be found, you likely have cyclic module usage in your code
共通部分も構造体として欲しい場合は、下記のようにすればできます。
common_struct.ex
defmodule CommonStruct do
defmacro __using__(attributes) do
quote do
CommonStruct.common_attributes() ++ unquote(attributes) |> defstruct
end
end
# defstruct, __using__で利用するためにモジュール変数に追い出す
@common_attributes [str: "", int: 0]
defstruct @common_attributes
def common_attributes(), do: @common_attributes
end
iex
iex(1)> i %CommonStruct{}
Term
%CommonStruct{int: 0, str: ""}
Data type
CommonStruct
Description
This is a struct. Structs are maps with a __struct__ key.
Reference modules
CommonStruct, Map
Implemented protocols
IEx.Info, Inspect
以上です!
皆さんによきElixirライフを