Documentation

@spec 可以類似定義介面一樣,定義函數的輸入輸出,下面是一個簡單的範例:

defmodule My do
  @spec sum(integer, integer) :: integer
  def sum(a, b) do
    a + b
  end
end

# 3
IO.puts My.sum(1, 2)

# (ArithmeticError) bad argument in arithmetic expression: 1 + "2"
IO.puts My.sum(1, "2")

因為 Elixir 是動態語言,要到執行階段才會丟 ArithmeticError 錯誤。

單純的輸入輸出下,@spec 即可運作良好,但如果複雜結構的話,就得接助 @type@type 可以自定義型別,並使用在 @spec 上。下面是一個簡單的範例:

defmodule People do
  @type t(name, age) :: %People{name: name, age: age}
  @type t :: %People{name: charlist, age: integer}
  defstruct name: nil, age: nil
end

defmodule Some do
  def run do
    a = %People{name: "some"}
    IO.puts a.name
    IO.puts a.age
  end
end

Some.run()

@spec 不同的是,定義型別對在某些情況下,並不會有約束力,但可以讓 IDE 工具使用。