ElixirSchool 项目教程:深入理解 Elixir 函数机制

ElixirSchool 项目教程:深入理解 Elixir 函数机制

elixirschool The content behind Elixir School elixirschool 项目地址: https://gitcode.com/gh_mirrors/el/elixirschool

前言

在函数式编程语言 Elixir 中,函数是一等公民,这意味着它们可以像其他数据类型一样被传递和操作。本文将全面解析 Elixir 中函数的各种特性和使用方式,帮助开发者掌握这一核心概念。

匿名函数基础

匿名函数是 Elixir 中最基础也是最重要的函数形式,它们没有名称但功能强大。

基本定义

使用 fnend 关键字定义匿名函数:

sum = fn (a, b) -> a + b end
sum.(2, 3)  # 返回 5

注意调用匿名函数时需要使用 . 运算符。

简写形式

Elixir 提供了更简洁的匿名函数定义方式:

sum = &(&1 + &2)
sum.(2, 3)  # 返回 5

在这种简写形式中:

  • &1 表示第一个参数
  • &2 表示第二个参数
  • 以此类推

模式匹配与函数

Elixir 的模式匹配特性同样适用于函数定义,这使得函数可以根据输入参数的不同形式执行不同的逻辑。

多子句函数

handle_result = fn
  {:ok, result} -> "处理结果..."
  {:ok, _} -> "这行不会执行"
  {:error} -> "发生错误!"
end

handle_result.({:ok, 1})  # 返回 "处理结果..."
handle_result.({:error})   # 返回 "发生错误!"

Elixir 会从上到下依次匹配,直到找到第一个匹配的子句。

命名函数详解

命名函数是模块化的基础,它们定义在模块内部,可以被其他模块调用。

基本定义

defmodule Greeter do
  def hello(name) do
    "Hello, " <> name
  end
end

Greeter.hello("Sean")  # 返回 "Hello, Sean"

单行简写

对于简单的函数体,可以使用 do: 简写:

defmodule Greeter do
  def hello(name), do: "Hello, " <> name
end

递归示例

命名函数非常适合实现递归算法:

defmodule Length do
  def of([]), do: 0
  def of([_ | tail]), do: 1 + of(tail)
end

Length.of([1, 2, 3])  # 返回 3

函数名称与元数

在 Elixir 中,函数由其名称和参数数量(元数)共同标识:

defmodule Greeter2 do
  def hello(), do: "Hello, anonymous!"  # hello/0
  def hello(name), do: "Hello, " <> name  # hello/1
  def hello(name1, name2), do: "Hello, #{name1} and #{name2}"  # hello/2
end

这些函数虽然同名但元数不同,在 Elixir 中被视为完全不同的函数。

高级模式匹配技巧

映射参数匹配

defmodule Greeter1 do
  def hello(%{name: person_name}) do
    "Hello, " <> person_name
  end
end

fred = %{name: "Fred", age: 95}
Greeter1.hello(fred)  # 返回 "Hello, Fred"

保留完整映射

如果需要同时访问特定键和整个映射:

defmodule Greeter2 do
  def hello(%{name: person_name} = person) do
    IO.puts "Hello, " <> person_name
    IO.inspect person
  end
end

这种写法会同时绑定 person_nameperson 两个变量。

私有函数

使用 defp 定义模块内部使用的私有函数:

defmodule Greeter do
  def hello(name), do: phrase() <> name
  defp phrase, do: "Hello, "
end

守卫子句

守卫子句可以基于参数条件选择不同的函数实现:

defmodule Greeter do
  def hello(names) when is_list(names) do
    Enum.join(names, ", ") |> hello()
  end

  def hello(name) when is_binary(name) do
    "Hello, " <> name
  end
end

默认参数处理

基本用法

defmodule Greeter do
  def hello(name, language_code \\ "en") do
    phrase(language_code) <> name
  end

  defp phrase("en"), do: "Hello, "
  defp phrase("es"), do: "Hola, "
end

多子句函数的默认参数

当多个函数子句需要默认参数时,应该这样处理:

defmodule Greeter do
  def hello(names, language_code \\ "en")

  def hello(names, language_code) when is_list(names) do
    Enum.join(names, ", ") |> hello(language_code)
  end

  def hello(name, language_code) when is_binary(name) do
    phrase(language_code) <> name
  end
end

总结

Elixir 的函数系统既强大又灵活,通过本文我们学习了:

  1. 匿名函数的定义和使用
  2. 命名函数的模块化组织
  3. 模式匹配在函数中的应用
  4. 守卫子句的条件判断
  5. 默认参数的合理使用

掌握这些概念是成为 Elixir 开发者的关键一步,建议读者通过实际编码练习来巩固这些知识。

elixirschool The content behind Elixir School elixirschool 项目地址: https://gitcode.com/gh_mirrors/el/elixirschool

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

羿恒新Odette

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值