Elixir高阶函数 #

一、高阶函数概念 #

1.1 什么是高阶函数 #

高阶函数是指接受函数作为参数或返回函数的函数。

1.2 Elixir中的高阶函数 #

elixir
iex(1)> Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]

iex(2)> Enum.filter([1, 2, 3, 4, 5], fn x -> x > 2 end)
[3, 4, 5]

iex(3)> Enum.reduce([1, 2, 3, 4, 5], 0, fn x, acc -> acc + x end)
15

二、管道操作符 #

2.1 基本用法 #

管道操作符 |> 将左边表达式的结果作为右边函数的第一个参数:

elixir
iex(1)> "hello" |> String.upcase()
"HELLO"

iex(2)> "hello" |> String.upcase() |> String.reverse()
"OLLEH"

2.2 等价形式 #

elixir
String.reverse(String.upcase("hello"))

"hello" |> String.upcase() |> String.reverse()

2.3 链式处理 #

elixir
defmodule DataProcessor do
  def process(data) do
    data
    |> Enum.filter(&valid?/1)
    |> Enum.map(&transform/1)
    |> Enum.sort()
    |> Enum.take(10)
  end

  defp valid?(item), do: item != nil
  defp transform(item), do: String.upcase(item)
end

2.4 与多参数函数 #

elixir
iex(1)> [1, 2, 3] |> Enum.map(&(&1 * 2))
[2, 4, 6]

iex(2)> "a,b,c" |> String.split(",")
["a", "b", "c"]

iex(3)> [1, 2, 3] |> Enum.join("-")
"1-2-3"

三、Enum模块 #

3.1 映射函数 #

map #

elixir
iex(1)> Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]

iex(2)> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]

map_every #

elixir
iex(1)> Enum.map_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2, fn x -> x * 2 end)
[2, 2, 6, 4, 10, 6, 14, 8, 18, 10]

flat_map #

elixir
iex(1)> Enum.flat_map([1, 2, 3], fn x -> [x, x * 2] end)
[1, 2, 2, 4, 3, 6]

3.2 过滤函数 #

filter #

elixir
iex(1)> Enum.filter([1, 2, 3, 4, 5], fn x -> x > 2 end)
[3, 4, 5]

iex(2)> Enum.filter([1, 2, nil, 4, nil], & &1)
[1, 2, 4]

reject #

elixir
iex(1)> Enum.reject([1, 2, 3, 4, 5], fn x -> x > 2 end)
[1, 2]

filter_map #

elixir
iex(1)> Enum.filter_map([1, 2, 3, 4, 5], fn x -> x > 2 end, fn x -> x * 2 end)
[6, 8, 10]

3.3 归约函数 #

reduce #

elixir
iex(1)> Enum.reduce([1, 2, 3, 4, 5], 0, fn x, acc -> acc + x end)
15

iex(2)> Enum.reduce([1, 2, 3, 4, 5], fn x, acc -> acc + x end)
15

iex(3)> Enum.reduce([1, 2, 3, 4, 5], [], fn x, acc -> [x | acc] end)
[5, 4, 3, 2, 1]

reduce_while #

elixir
iex(1)> Enum.reduce_while([1, 2, 3, 4, 5], 0, fn x, acc ->
...>   if x < 4, do: {:cont, acc + x}, else: {:halt, acc}
...> end)
6

3.4 查找函数 #

find #

elixir
iex(1)> Enum.find([1, 2, 3, 4, 5], fn x -> x > 2 end)
3

iex(2)> Enum.find([1, 2, 3, 4, 5], fn x -> x > 10 end)
nil

iex(3)> Enum.find([1, 2, 3, 4, 5], 0, fn x -> x > 10 end)
0

find_value #

elixir
iex(1)> Enum.find_value([1, 2, 3, 4, 5], fn x -> if x > 2, do: x * 2 end)
6

find_index #

elixir
iex(1)> Enum.find_index([1, 2, 3, 4, 5], fn x -> x > 2 end)
2

3.5 排序函数 #

sort #

elixir
iex(1)> Enum.sort([3, 1, 4, 1, 5, 9])
[1, 1, 3, 4, 5, 9]

iex(2)> Enum.sort([3, 1, 4, 1, 5, 9], :desc)
[9, 5, 4, 3, 1, 1]

sort_by #

elixir
iex(1)> users = [%{name: "Alice", age: 30}, %{name: "Bob", age: 25}]
[%{age: 30, name: "Alice"}, %{age: 25, name: "Bob"}]

iex(2)> Enum.sort_by(users, & &1.age)
[%{age: 25, name: "Bob"}, %{age: 30, name: "Alice"}]

3.6 分组函数 #

chunk_every #

elixir
iex(1)> Enum.chunk_every([1, 2, 3, 4, 5, 6], 2)
[[1, 2], [3, 4], [5, 6]]

iex(2)> Enum.chunk_every([1, 2, 3, 4, 5], 2, 1)
[[1, 2], [2, 3], [3, 4], [4, 5]]

group_by #

elixir
iex(1)> Enum.group_by(["apple", "banana", "apricot"], fn x -> String.first(x) end)
%{"a" => ["apple", "apricot"], "b" => ["banana"]}

split #

elixir
iex(1)> Enum.split([1, 2, 3, 4, 5], 3)
{[1, 2, 3], [4, 5]}

iex(2)> Enum.split_with([1, 2, 3, 4, 5], fn x -> x > 2 end)
{[3, 4, 5], [1, 2]}

3.7 聚合函数 #

elixir
iex(1)> Enum.sum([1, 2, 3, 4, 5])
15

iex(2)> Enum.product([1, 2, 3, 4, 5])
120

iex(3)> Enum.min([3, 1, 4, 1, 5, 9])
1

iex(4)> Enum.max([3, 1, 4, 1, 5, 9])
9

iex(5)> Enum.min_max([3, 1, 4, 1, 5, 9])
{1, 9}

iex(6)> Enum.count([1, 2, 3, 4, 5])
5

iex(7)> Enum.count([1, 2, 3, 4, 5], fn x -> x > 2 end)
3

3.8 成员检查 #

elixir
iex(1)> Enum.member?([1, 2, 3, 4, 5], 3)
true

iex(2)> Enum.any?([1, 2, 3, 4, 5], fn x -> x > 3 end)
true

iex(3)> Enum.all?([1, 2, 3, 4, 5], fn x -> x > 0 end)
true

iex(4)> Enum.empty?([])
true

四、Stream模块 #

4.1 惰性序列 #

Stream是惰性的,只在需要时计算:

elixir
iex(1)> stream = Stream.map(1..100_000, &(&1 * 2))
#Stream<[enum: 1..100000, funs: [#Function<...>]]>

iex(2)> Enum.take(stream, 5)
[2, 4, 6, 8, 10]

4.2 无限序列 #

elixir
iex(1)> Stream.cycle([1, 2, 3]) |> Enum.take(10)
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]

iex(2)> Stream.iterate(1, &(&1 * 2)) |> Enum.take(10)
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

iex(3)> Stream.unfold(0, fn n -> {n, n + 1} end) |> Enum.take(5)
[0, 1, 2, 3, 4]

4.3 链式操作 #

elixir
iex(1)> 1..100_000
...> |> Stream.map(&(&1 * 2))
...> |> Stream.filter(&(rem(&1, 3) == 0))
...> |> Enum.take(5)
[6, 12, 18, 24, 30]

4.4 文件处理 #

elixir
"large_file.txt"
|> File.stream!()
|> Stream.map(&String.trim/1)
|> Stream.filter(&(String.length(&1) > 0))
|> Enum.take(100)

五、列表推导式 #

5.1 基本语法 #

elixir
iex(1)> for x <- [1, 2, 3], do: x * 2
[2, 4, 6]

5.2 多生成器 #

elixir
iex(1)> for x <- [1, 2], y <- [3, 4], do: {x, y}
[{1, 3}, {1, 4}, {2, 3}, {2, 4}]

5.3 过滤 #

elixir
iex(1)> for x <- 1..10, x > 5, do: x
[6, 7, 8, 9, 10]

iex(2)> for x <- 1..10, rem(x, 2) == 0, do: x
[2, 4, 6, 8, 10]

5.4 解构 #

elixir
iex(1)> users = [%{name: "Alice", age: 30}, %{name: "Bob", age: 25}]
[%{age: 30, name: "Alice"}, %{age: 25, name: "Bob"}]

iex(2)> for %{name: name} <- users, do: name
["Alice", "Bob"]

5.5 转换结果类型 #

elixir
iex(1)> for x <- 1..5, into: %{}, do: {x, x * 2}
%{1 => 2, 2 => 4, 3 => 6, 4 => 8, 5 => 10}

iex(2)> for x <- 1..5, into: "", do: <<x + 96>>
"abcde"

六、实用示例 #

6.1 数据处理管道 #

elixir
defmodule DataPipeline do
  def process(file_path) do
    file_path
    |> File.stream!()
    |> Stream.drop(1)
    |> Stream.map(&parse_line/1)
    |> Stream.filter(&valid?/1)
    |> Enum.reduce(%{}, &aggregate/2)
  end

  defp parse_line(line) do
    line
    |> String.trim()
    |> String.split(",")
    |> List.to_tuple()
  end

  defp valid?({_date, value}), do: String.to_integer(value) > 0

  defp aggregate({_date, value}, acc) do
    Map.update(acc, :total, 0, &(&1 + String.to_integer(value)))
  end
end

6.2 文本分析 #

elixir
defmodule TextAnalyzer do
  def word_frequency(text) do
    text
    |> String.downcase()
    |> String.split(~r/\W+/, trim: true)
    |> Enum.reduce(%{}, fn word, acc ->
      Map.update(acc, word, 1, &(&1 + 1))
    end)
    |> Enum.sort_by(fn {_word, count} -> count end, :desc)
    |> Enum.take(10)
  end
end

七、总结 #

本章学习了:

函数 用途
Enum.map/2 映射转换
Enum.filter/2 过滤元素
Enum.reduce/3 归约聚合
Enum.find/2 查找元素
Enum.sort/2 排序
Enum.group_by/2 分组
Stream 惰性序列
for 列表推导式
|> 管道操作符

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

最后更新:2026-03-27