第 R2 站 · 可选复习展开探险地图
00装好工具前置准备01起跑线前置准备02进程与信箱R1Elixir 数据流水线可选复习R2读懂 Erlang可选复习03消息与超时04OTP 消息章法05会重启的监督树06给并发设上限07BEAM 节点失联X1两种语言对暗号双语扩展X2双语搭档双语扩展08可靠任务调度器
首页/BEAM 主线/第 R2 站
R2
语言入门探索可选复习Erlang

读懂 Erlang

从大小写开始,再读懂逗号、分号和句点给出的路标。

5小关卡
约 6 小时 · 建议分 5 次可以分几次
QUESTION · 本站只追这一问

【语言跳级复习】怎样用 Erlang 重做同一份日志工具,并让两种实现遵守同一输入输出契约?

先看现场

两份实现通过了各自测试,却给出不同结果

Elixir 与 Erlang 的解析器各自通过测试,遇到空行、WARN 或坏格式时却给出不同结果。原因藏在导出函数、标点、模式和输入约定里。

能够观察到
  • 两种实现共用的输入样例与预期结果
  • 导出函数列表,以及编译器给出的第一条错误
  • 空行、INFO、WARN 与坏格式输入的并排输出
为什么学这一站

它要解决什么

不少 BEAM 文档和工具使用 Erlang。看懂基础写法,就能读懂错误信息、:gen_tcp 和 observer。先从数据、函数与标点开始。

走完这一站

你会做到

  • 能认出 Erlang 中的 atom、变量、tuple、list、map 和 binary

  • 能用逗号、分号和句点写清“接着做”“换条路”和“到这里结束”

  • 能创建 Rebar3 项目,并用 EUnit 检查自己的函数

出发前
  • 完成 Elixir 基础,能看懂上一关的日志处理步骤
  • 知道模式匹配是在检查数据形状,并见过函数再次调用自己
同一件事,两种写法

先看做什么,再看怎么写

Erlang 模块名是 atom。total/1 中的 1 表示函数接收一个参数。列表推导会用形状模板挑出已付款订单,再取金额。

当前代码
Elixir
# 计算所有已付款订单的总金额
defmodule Orders do
  def total(items) do
    # 先筛选状态,再取出金额并相加
    items
    |> Enum.filter(&(&1.status == :paid))
    |> Enum.map(& &1.amount)
    |> Enum.sum()
  end
end
LAB
动手

给 Erlang 代码断句

约 15–25 分钟

分别改错逗号、分号和句点。别背报错,找出编译器认为哪一段还没结束。

  1. 01

    创建 classify/1,为正数和零或负数准备两个入口

  2. 02

    把第一条入口末尾的分号改成句点,再编译一次

  3. 03

    把同一个函数体中表示“接着做”的逗号改成分号,再编译一次

复制到终端,按回车
# 编译项目,并运行全部 EUnit 测试
rebar3 eunit
你会看到
  • 分号能隔开同名、同参数个数的多个函数入口
  • 句点会告诉编译器:整个函数定义到这里结束
  • 逗号会让同一函数体中的表达式按顺序继续
故意弄坏

删掉 -export([total/1]).,再从 shell 调用。函数仍在模块里,但外部无法访问。

这次能看清

Erlang 的逗号、分号和句点都在表达代码结构,不能只按好看与否互换。

这次还不能说明

成功编译只说明结构基本正确,还不能说明程序算出的答案一定正确。

先认词

这段代码里的关键词

01

大写变量

在 Erlang 中,大写字母或下划线开头的名字表示变量;小写裸词通常是一个固定标签,叫 atom。

02

标点结构

逗号连接顺序表达式,分号隔开函数子句或分支,句点结束完整定义或 shell 表达式。

03

binary

装着一串字节的数据盒子,写作 <<...>>。UTF-8 文本通常放在 binary 中;传统 charlist 则是一串代表字符的整数。

从代码里认出章法

这里用了哪些设计模式

01

Contract Test

用同一组样例约束两种语言的输入与输出。

02

Ports and Adapters

把语言特有实现藏在共同契约后面。

想一想

Erlang 看到没有引号的 user_name 时,会把它当成什么?

轮到你

翻译一段 Erlang

用 Rebar3 重写日志工具,让两种实现读取同一组样例并返回相同结果。

提示 1先迈一步

可以用 binary 的形状模板拆出 INFO、WARN 和 ERROR 前缀。

提示 2再缩小一点

读取文件放在单独模块里,整理日志的核心函数只接收 binary 列表。

提示 3离答案很近了

把上一关的测试场景带过来;EUnit 测试可以使用 _test 或 generator 写法。

提示 4从终点往回想

先挑一条“过关信号”,为它写一个最小测试。如果电脑看不出结果,就把这句话改成一个真正能观察到的现象。

过关条件
  • 模块只打开真正需要从外部进入的函数入口

  • 代码会明确分清 binary 和 charlist,并在需要时转换

  • EUnit 检查了与 Elixir 版相同的正常、边角和错误场景

带走

记住三句话

  1. 1

    Erlang 会直接写出模块、函数和参数个数,这些信息就像函数的完整地址。

  2. 2

    binary 和 charlist 不是同一种数据;两种语言交换文本时,要主动看清并转换。

  3. 3

    逗号、分号和句点都是结构路标,不只是书写习惯。

再读一点

去看原版资料

Erlang Reference ManualRebar3EUnit
本站结束实验做过,答案也想过,就把这一站收好。