公式ドキュメントや、コード見ていて知った型定義の方法をまとめ
@type <type name>
は型指定で使用する特殊な記法。慣習として、<type name>
はt
で記載されることが多い。例) @type t :: :dev | :stg | :pro
typespec
は厳格さを保証してくれない。厳格にさせたい場合はDializer
などを使う必要がある。ただし、実行自体に時間がかかるようなので、プロジェクト規模やメンバ感で相談して導入検討を行うとよいと思うmap
typespecmap
としてtypespec定義defmodule M1 do
@spec sum(map) :: integer
def sum(params) do
%{a: a, b: b} = params
a + b
end
end
type attribute Struct
によるtypespec
type attribute
を実装したStruct
を作成し、そのStruct
をtypespec
で定義Struct
要素の型の責任をStruct3
に持たせられる
defmodule Struct3 do
defstruct a: 999, b: 888
@type t :: %Struct3{a: integer, b: integer}
end
defmodule M do
@spec sum(Struct3.t) :: integer
def sum(params) do
%{a: a, b: b} = params
a + b
end
end
type attribute
を使用して独自型を作成Module
に定義できるので手軽に記載できるdefmodule M5 do
@type type :: :sum | :diff
@spec calc(type, map) :: integer
def calc(type, %{a: a, b: b} = _maps) do
case type do
:sum -> a + b
:diff -> a - b
end
end
end
map
typespectypespec
で定義するくらいなら、関数に直接定義したほうが厳格さも出せるので
defmodule M2 do
@spec sum(%{a: integer, b: integer}) :: integer
def sum(params) do
%{a: a, b: b} = params
a + b
end
end
Struct
で定義したtypespecStruct
を作成し、そのStruct
をtypespec
で定義defmodule Struct3 do
defstruct [:a, :b]
end
defmodule M3 do
@spec sum(%Struct3{a: integer, b: integer}) :: integer
def sum(params) do
%{a: a, b: b} = params
a + b
end
end
type attribute(引数あり)
のtypespectype attribute
を実装したStruct
を作成し、そのStruct
をtypespec
で定義Struct2
の構造体は決まっているが、実行される関数によって要素の型や使われる要素が変動するケースで利用できる。ただ、記載が複雑だし、ここまで厳格に書くことは少ないと思うし、そもそも、そのようなケースの場合は、やはり引数に要素を明示して厳格さを保つほうがベターだと思う。defmodule Struct2 do
defstruct [:a, :b]
@type t(a, b) :: %Struct2{a: a, b: b}
end
defmodule M4 do
@spec sum(Struct2.t(integer, integer)) :: integer
def sum(params) do
%{a: a, b: b} = params
a + b
end
end