Erlang 从零 · 第 11 课(展开目录)
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 1130 分钟

一层一层取数据

从 map 里的 list 读取值,再产生更新后的嵌套结构。

01 · 先看完整例子

读取并更新课程积分

最后同时查看课程名与新积分。

Erlang
Student = #{
  name => <<"A-Qing">>,
  courses => [#{title => <<"Erlang">>, points => 8}]
},

%% 先取课程 list,再匹配第一项
[Course | _] = maps:get(courses, Student),
Title = maps:get(title, Course),

%% 更新内层后,再放回外层 map
UpdatedCourse = Course#{points := 9},
Updated = Student#{courses := [UpdatedCourse]},
{Title, maps:get(points, hd(maps:get(courses, Updated)))}.
先对照结果
  • 得到 {<<"Erlang">>,9};Student 中的原积分仍为 8。
02 · 回头拆代码

从第一行往下读

  1. 先把嵌套读取拆成多个有名字的步骤。
  2. 内层课程 map 更新后,外层也要放入新课程 list。
  3. 所有更新都生成新 term。
03 · 认清新符号

符号不是暗号

maps:get(Key, Map)

读取 map 中指定键的值。

Map#{key := value}

更新已经存在的键。

[Head | Tail]

匹配非空 list 的第一项与剩余部分。

04 · 代码里的概念

把名字和意思对上

01

嵌套 term

一个集合中继续放其他集合,如 map 里放课程 list。

02

map 更新

从旧 map 产生带新值的新 map;原值不改变。

05 · 再说清楚

这些写法为什么有用

真实数据常由 map、list 和 tuple 叠在一起。先匹配外层,再处理内层,别一眼吞下整棵树。

maps:get/2 读取键。更新 map 使用 #{key := value},它返回新 map。

list 的头尾模式能取第一项。若 list 可能为空,应写出空 list 分支。

06 · 自己改一次

合上答案,动手

把 #{profile => #{city => <<"Xi'an">>}} 的城市改为 <<"Chengdu">>。

练习起点
Person = #{profile => #{city => <<"Xi'an">>}},
Profile = maps:get(____, Person),
Person#{profile := Profile#{city := ____}}.

目标结果: 新 map 的城市是 <<"Chengdu">>。

卡住了,再看提示

外层键是 profile,新值是一个 binary。

运行过以后,再看一种答案
一种答案
Person = #{profile => #{city => <<"Xi'an">>}},
Profile = maps:get(profile, Person),
%% 先更新内层,再放回外层
Person#{profile := Profile#{city := <<"Chengdu">>}}.
想一想:`Map#{key := value}` 会直接改掉 `Map` 吗?

不会。它返回新 map;旧变量仍指向旧值。

带走

记住三句

  1. 1

    嵌套数据要分层读取。

  2. 2

    := 更新已存在的 map 键。

  3. 3

    旧 term 不会被原地修改。

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