Erlang 从零 · 第 04 课(展开目录)
01 · 先打开 erl02 · 先认常见 term03 · 分清两种文字04 · 变量只接一次05 · 拆开一列,再筛一次06 · 把文字安全变成整数07 · 用 case 选一条路08 · 让函数继续走09 · 把代码放进模块10 · 条件必须说真话11 · 一层一层取数据12 · 文字先说清编码13 · 让函数子句排好队14 · 带着累加器往前走15 · 先看值,再选路16 · 给模块立规矩17 · 让 rebar3 管项目18 · 让结果有固定形状19 · 把磁盘当成会失败的邻居20 · 把函数交给 list21 · record 留在院里22 · 先写模块之间的约定23 · 把 term 形状写出来24 · 小测试与整段路25 · 把应用磨成命令26 · 先把小项目圈住27 · 把真实文件洗干净28 · 公开入口越少越稳29 · 把约定留在源码旁30 · 打包,也留下线索31 · 按最初任务交卷
ERLANG · 试跑 · LESSON 0425 分钟

变量只接一次

认识大写变量、单次赋值和模式匹配。

01 · 先看完整例子

左边是形状,右边是数据

map 的创建使用 =>,模式匹配已有 key 时使用 :=。

Erlang
%% 先清掉 shell 中已有的变量绑定
f().

%% 标签 ok 必须对上,Score 接住 92
{ok, Score} = {ok, 92}.

%% map 模式取值,再核对已绑定变量
#{name := Name} = #{name => <<"A-Qing">>, age => 12}.
92 = Score.
{Score, Name}.
先对照结果
  • Score 绑定到 92。
  • Name 绑定到 <<"A-Qing">>。
  • 最后得到 {92, <<"A-Qing">>}。
02 · 回头拆代码

从第一行往下读

  1. {ok, Score} 要求右边是两个元素的 tuple,而且第一个必须是 atom ok。
  2. #{name := Name} 是 map 模式。它寻找已有 key name,让 Name 接住对应值。
  3. 92 = Score 能成功,因为 Score 已经是 92;写 93 = Score 会 badmatch。
03 · 认清新符号

符号不是暗号

Name

大写开头,是变量。

name

小写开头,是 atom。

_

匹配这个位置,但不保存它的值。

f().

只在 Erlang shell 使用:清掉当前 shell 里已有的变量绑定。

04 · 代码里的概念

把名字和意思对上

01

变量

以大写字母或下划线开头的名字,如 Name、_Rest。

02

单次赋值

一个变量接住值后,在当前作用域中不能改成另一个值。

03

匹配

检查左右形状,并让新变量接住对应位置的值。

05 · 再说清楚

这些写法为什么有用

Erlang 变量必须以大写字母或下划线开头。Score 是变量,score 是 atom。

变量在一次匹配中接住值后,不能再改绑到另一个值。这叫单次赋值。

= 是匹配运算符。左边写形状,右边给数据;形状对不上时会出现 badmatch。

设计选择

为什么这样写

为什么不把 = 只当作赋值?

这次选择

模式把“检查形状”和“取出数据”合在一次操作里。函数入口、case 和 receive 因此能用同一套读法。

代价与边界

跨一次新的匹配时,两门语言规则不同:Elixir 的名字默认可以重新绑定,要用 ^name 才核对旧值;Erlang 的变量一旦绑定,再出现在模式里就会核对。

换一把尺子

从 Java、Python、JavaScript 看过来

Java

熟悉的起点
局部变量赋值,再用 getter 或 instanceof 检查对象。
BEAM 在意什么
模式直接检查 tuple、list 或 map 的形状并取值。
别带错直觉
这里不是方法重载,也不会修改右边的数据。

Python

熟悉的起点
解包和 match/case 已有相近感觉。
BEAM 在意什么
数据不会被原地改写,模式也是函数子句和消息协议的日常工具。
别带错直觉
Elixir 可以重新绑定名字,但不会改掉原值;Erlang 的已绑定变量会用来核对。

JavaScript

熟悉的起点
数组、对象解构主要负责取值。
BEAM 在意什么
BEAM 模式还会核对固定标签;不匹配会走别的子句或失败。
别带错直觉
对象解构的默认值与 BEAM 模式不是同一套规则。
06 · 自己改一次

合上答案,动手

从 {weather, <<"Xi'an">>, 28} 中拆出城市和温度。

练习起点
%% 清掉示例和前几课留下的变量
f().

%% 固定标签必须对上,变量用大写开头
{____, ____, ____} = {weather, <<"Xi'an">>, 28}.

%% 查看拆出的值
{City, Temperature}.

目标结果: 得到 {<<"Xi'an">>, 28}。

卡住了,再看提示

左边依次写 atom weather、变量 City、变量 Temperature。

运行过以后,再看一种答案
一种答案
%% f() 只属于 shell,不要写进 .erl 文件
f().

%% atom 核对标签,变量接住数据
{weather, City, Temperature} = {weather, <<"Xi'an">>, 28}.

%% 变量已经分别绑定
{City, Temperature}.
想一想:已经执行 `Count = 3.` 后,再执行 `Count = 4.` 会怎样?

会出现 badmatch。Count 已绑定到 3,不能再接住不同的值 4。

带走

记住三句

  1. 1

    大写开头是变量,小写开头通常是 atom。

  2. 2

    Erlang 变量一旦绑定就不能改值。

  3. 3

    = 会进行模式匹配。

本课结束代码也跑过一次,就把这一课收好。