Elixir命名函数 #

一、函数定义 #

1.1 基本语法 #

命名函数必须在模块内定义:

elixir
defmodule Math do
  def add(a, b) do
    a + b
  end

  def subtract(a, b) do
    a - b
  end
end

1.2 调用函数 #

elixir
iex(1)> Math.add(1, 2)
3

iex(2)> Math.subtract(5, 3)
2

1.3 单行语法 #

elixir
defmodule Math do
  def add(a, b), do: a + b
  def subtract(a, b), do: a - b
  def multiply(a, b), do: a * b
end

1.4 函数体 #

elixir
defmodule Calculator do
  def calculate(a, b, operation) do
    result = operation.(a, b)
    IO.puts("Result: #{result}")
    result
  end
end

二、多子句函数 #

2.1 基本模式匹配 #

elixir
defmodule ListUtils do
  def first([head | _]), do: head
  def first([]), do: nil

  def last([x]), do: x
  def last([_ | tail]), do: last(tail)
  def last([]), do: nil
end

2.2 带守卫的子句 #

elixir
defmodule Math do
  def abs(x) when x < 0, do: -x
  def abs(x), do: x

  def sign(x) when x > 0, do: 1
  def sign(x) when x < 0, do: -1
  def sign(0), do: 0

  def factorial(0), do: 1
  def factorial(n) when n > 0, do: n * factorial(n - 1)
end

2.3 元组模式匹配 #

elixir
defmodule Result do
  def handle({:ok, result}), do: result
  def handle({:error, reason}), do: {:error, reason}

  def process({:ok, data}) do
    {:ok, transform(data)}
  end

  def process({:error, reason}) do
    {:error, reason}
  end

  defp transform(data), do: String.upcase(data)
end

2.4 映射模式匹配 #

elixir
defmodule User do
  def greet(%{name: name, role: :admin}), do: "Hello, Admin #{name}!"
  def greet(%{name: name, role: :user}), do: "Hello, #{name}!"
  def greet(%{name: name}), do: "Hi, #{name}!"
  def greet(_), do: "Hello, stranger!"
end

2.5 子句顺序 #

子句按顺序匹配,更具体的子句应放在前面:

elixir
defmodule Example do
  def process(%{type: :special, value: value}), do: "Special: #{value}"
  def process(%{type: :normal, value: value}), do: "Normal: #{value}"
  def process(%{value: value}), do: "Generic: #{value}"
  def process(_), do: "Unknown"
end

三、默认参数 #

3.1 基本语法 #

elixir
defmodule Greeter do
  def greet(name, greeting \\ "Hello") do
    "#{greeting}, #{name}!"
  end
end

Greeter.greet("Alice")
Greeter.greet("Alice", "Hi")

3.2 多个默认参数 #

elixir
defmodule Config do
  def build(host \\ "localhost", port \\ 8080, ssl \\ false) do
    %{host: host, port: port, ssl: ssl}
  end
end

Config.build()
Config.build("example.com")
Config.build("example.com", 443)
Config.build("example.com", 443, true)

3.3 默认参数与守卫 #

elixir
defmodule Math do
  def power(base, exponent \\ 2)
  def power(base, exponent) when exponent > 0 do
    :math.pow(base, exponent)
  end
  def power(base, 0), do: 1
end

3.4 默认参数与模式匹配 #

当使用默认参数和多子句时,需要函数头声明:

elixir
defmodule Example do
  def func(arg1, arg2 \\ "default")

  def func(arg1, arg2) when is_binary(arg1) do
    "#{arg1}: #{arg2}"
  end

  def func(arg1, arg2) when is_integer(arg1) do
    "#{arg1}: #{arg2}"
  end
end

四、私有函数 #

4.1 defp #

使用 defp 定义私有函数:

elixir
defmodule Calculator do
  def calculate(a, b, operation) do
    result = do_calculate(a, b, operation)
    format_result(result)
  end

  defp do_calculate(a, b, :add), do: a + b
  defp do_calculate(a, b, :subtract), do: a - b
  defp do_calculate(a, b, :multiply), do: a * b
  defp do_calculate(a, b, :divide), do: a / b

  defp format_result(result) when is_float(result) do
    Float.round(result, 2)
  end

  defp format_result(result), do: result
end

4.2 公共接口与私有实现 #

elixir
defmodule UserStore do
  def create(attrs) do
    with {:ok, validated} <- validate(attrs),
         {:ok, user} <- persist(validated) do
      {:ok, user}
    end
  end

  def find(id) do
    case fetch(id) do
      {:ok, user} -> {:ok, format(user)}
      :error -> {:error, :not_found}
    end
  end

  defp validate(attrs) do
    if attrs[:name] && attrs[:email] do
      {:ok, attrs}
    else
      {:error, :invalid_attributes}
    end
  end

  defp persist(attrs) do
    {:ok, Map.put(attrs, :id, generate_id())}
  end

  defp fetch(id) do
    {:ok, %{id: id, name: "User #{id}"}}
  end

  defp format(user) do
    Map.put(user, :formatted_name, String.upcase(user[:name]))
  end

  defp generate_id do
    :rand.uniform(1000)
  end
end

五、函数文档 #

5.1 @doc #

elixir
defmodule Math do
  @doc """
  Adds two numbers together.

  ## Parameters

    - `a` - The first number
    - `b` - The second number

  ## Examples

      iex> Math.add(1, 2)
      3

      iex> Math.add(1.5, 2.5)
      4.0

  """
  def add(a, b), do: a + b
end

5.2 查看文档 #

elixir
iex(1)> h(Math.add)

5.3 @spec #

elixir
defmodule Math do
  @spec add(number(), number()) :: number()
  def add(a, b), do: a + b

  @spec divide(number(), number()) :: {:ok, number()} | {:error, :division_by_zero}
  def divide(_, 0), do: {:error, :division_by_zero}
  def divide(a, b), do: {:ok, a / b}
end

六、函数类型规范 #

6.1 基本类型 #

elixir
@spec id(any()) :: any()
def id(x), do: x

@spec length(list()) :: non_neg_integer()
def length(list), do: :erlang.length(list)

@spec concat(binary(), binary()) :: binary()
def concat(a, b), do: a <> b

6.2 自定义类型 #

elixir
defmodule User do
  @type t :: %__MODULE__{
    id: integer(),
    name: String.t(),
    email: String.t()
  }

  defstruct [:id, :name, :email]

  @spec new(String.t(), String.t()) :: t()
  def new(name, email) do
    %__MODULE__{id: generate_id(), name: name, email: email}
  end

  defp generate_id, do: :rand.uniform(1000)
end

七、函数捕获 #

7.1 捕获命名函数 #

elixir
iex(1)> add = &Math.add/2
&Math.add/2

iex(2)> add.(1, 2)
3

iex(3)> Enum.map([1, 2, 3], &Math.add(&1, 1))
[2, 3, 4]

7.2 在模块内捕获 #

elixir
defmodule Example do
  def double(x), do: x * 2

  def process_list(list) do
    Enum.map(list, &double/1)
  end
end

八、函数可见性 #

8.1 公共函数 #

elixir
defmodule Public do
  def public_function do
    "This is public"
  end
end

8.2 私有函数 #

elixir
defmodule Private do
  def public_function do
    private_helper()
  end

  defp private_helper do
    "This is private"
  end
end

8.3 函数委托 #

elixir
defmodule Wrapper do
  defdelegate upcase(string), to: String
  defdelegate reverse(string), to: String
end

Wrapper.upcase("hello")
Wrapper.reverse("hello")

九、最佳实践 #

9.1 函数命名 #

elixir
defmodule Naming do
  def valid?(data), do: data != nil

  def parse!(string) do
    case Integer.parse(string) do
      {number, ""} -> number
      _ -> raise "Invalid integer"
    end
  end

  def parse(string) do
    case Integer.parse(string) do
      {number, ""} -> {:ok, number}
      _ -> {:error, :invalid_integer}
    end
  end
end

9.2 函数组织 #

elixir
defmodule WellOrganized do
  defstruct [:id, :name]

  @type t :: %__MODULE__{id: integer(), name: String.t()}

  @doc "Public API"
  def create(attrs), do: do_create(attrs)

  def find(id), do: do_find(id)

  def update(struct, attrs), do: do_update(struct, attrs)

  def delete(id), do: do_delete(id)

  defp do_create(attrs), do: {:ok, struct(__MODULE__, attrs)}

  defp do_find(_id), do: {:ok, %__MODULE__{}}

  defp do_update(struct, attrs), do: {:ok, struct(struct, attrs)}

  defp do_delete(_id), do: :ok
end

十、总结 #

本章学习了:

特性 示例
定义 def func(arg), do: result
私有函数 defp func(arg), do: result
多子句 def handle({:ok, x}), do: x
守卫 def abs(x) when x < 0, do: -x
默认参数 def greet(name, msg \\ "Hello")
文档 @doc "Description"
类型规范 @spec add(number, number) :: number

准备好学习递归了吗?让我们进入下一章。

最后更新:2026-03-27