模块 02查看课程目录
02
语言入门Elixir
Elixir 基础:让数据流过函数
模式匹配、多子句函数、Enum 与管道,不是四个孤立语法点。
5检查点
6 小时预计完成
为什么先学这个
先修正心智模型,再增加 API
Elixir 最容易被写成带管道符的命令式代码:到处 if、在一条长管道里混合解析与副作用。更稳的做法是先用模式匹配定义数据形状,再让每个小函数只承担一个转换。
学完你能做到
可验证的学习目标
- 能使用模式匹配、guard 与多子句函数表达分支
- 能在 Enum 与 Stream 之间做有理由的选择
- 能为纯函数编写最小 ExUnit 测试
前置知识
- 完成 BEAM 心智模型
- 知道 list 与 map 的用途
最小心智模型
先抓住三个词
模式匹配
`=` 不是普通赋值。它要求右侧数据符合左侧形状,并把未绑定变量绑定到对应位置。
多子句函数
同名同元数的函数可按模式和 guard 分成多条路径,调用时从上到下匹配。
管道
`|>` 把左侧结果作为右侧函数的第一个参数;它改善数据流可读性,但不会自动改善函数边界。
双语代码桥
先对齐协议,再看标点
先看 Elixir 主实现,再用右侧 Erlang 轮廓确认:真正共享的是模式与数据,不是标点。
Elixir
defmodule LogSummary do
def summarize(lines) do
lines
|> Stream.map(&String.trim/1)
|> Stream.reject(&(&1 == ""))
|> Enum.map(&parse_line/1)
|> Enum.frequencies_by(& &1.level)
end
defp parse_line("ERROR " <> message),
do: %{level: :error, message: message}
defp parse_line("INFO " <> message),
do: %{level: :info, message: message}
endErlang
%% 同一数据流的 Erlang 轮廓
summarize(Lines) ->
Clean = [string:trim(L) || L <- Lines, L =/= <<>>],
Parsed = [parse_line(L) || L <- Clean],
frequencies(Parsed).
parse_line(<<"ERROR ", Message/binary>>) ->
#{level => error, message => Message};
parse_line(<<"INFO ", Message/binary>>) ->
#{level => info, message => Message}.LAB
约 15–25 分钟可运行实验
管道顺序为什么是语义,不是排版
给解析器加入空行和前后空格。交换 trim 与 reject 的顺序,看一条看似无害的调整如何改变结果。
- 01
准备 `[' INFO boot ', ' ', 'ERROR timeout']` 对应的 Elixir 字符串列表
- 02
运行原顺序并记录频次
- 03
把 reject 移到 trim 之前,再运行同一输入
在终端 / shell 中运行
mix test --trace预期观察
- 先 trim 再 reject 时,纯空格行被删除
- 先 reject 再 trim 时,纯空格行会进入解析器
故意弄坏
把兜底 `parse_line/1` 删掉,再传入 `WARN slow`。观察 FunctionClauseError 中保留了哪些定位信息。
这个实验能证明
数据转换顺序会改变可匹配的数据集合。
这个实验不能证明
这个小样本不能证明 Stream 一定更快;是否受益取决于数据量、终止条件与后续消费方式。
快速自测
什么时候优先使用 Stream 而不是 Enum?
本章挑战
命令行日志分析器
实现一个 Mix 项目:读取日志文件,忽略空行,统计 INFO/WARN/ERROR,并列出出现次数最多的三个消息。
提示 1轻推一下
先让解析函数保持纯净,再把文件 I/O 放到边界。
提示 2缩小问题
为未知级别返回 `{:error, line}`,不要悄悄丢弃。
提示 3接近实现
至少写一个带空格、一个未知级别、一个空文件测试。
提示 4用验收标准反推
从下面每一条验收标准倒推一个最小测试。若某条无法写成测试,先把表述改成可观察结果。
完成标准
- 解析与文件读取分离
- 未知行有显式错误结果
- ExUnit 覆盖正常、边界与错误路径
带走这三句话
复习卡
- 1先定义数据形状,再定义转换流水线。
- 2管道只是参数传递语法;好设计仍依赖小而清晰的函数。
- 3Stream 是惰性工具,不是“更快版 Enum”。
继续核对