Erlang 从零 · 第 16 课(展开目录)
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 1640 分钟
给模块立规矩
用模块属性声明身份、导出、常量和 record 字段。
01 · 先看完整例子
保存为 library.erl
编译后运行 B = library:new(<<"Small Town">>), library:info(B).。
Erlang
-module(library).
-export([new/1, info/1]).
-define(DEFAULT_PAGES, 1).
-record(book, {title, pages = ?DEFAULT_PAGES}).
%% record 只在知道定义的模块中展开
new(Title) ->
#book{title = Title}.
info(Book) ->
{Book#book.title, Book#book.pages}.先对照结果
- 得到
{<<"Small Town">>,1}。
02 · 回头拆代码
从第一行往下读
- 宏给默认页数一个名字,编译时会展开。
- record 字段让代码不用记 tuple 的位置。
- 公开
info/1避免调用者直接依赖 record 内部布局。
03 · 认清新符号
符号不是暗号
-define(NAME, Value).声明宏,使用时写 ?NAME。
-record(name, {...}).声明 record 字段与默认值。
#book{...}创建、匹配或更新 book record。
04 · 代码里的概念
把名字和意思对上
模块属性
告诉编译器模块身份、公开函数、类型等信息的声明。
record
为固定 tuple 位置提供字段名的编译期语法。
05 · 再说清楚
这些写法为什么有用
Erlang 模块属性以连字符开头,编译时生效。-module、-export 都是属性。
-define 声明宏常量。record 为 tuple 字段提供名字,但它主要是编译期语法,不是全局运行时类型。
record 定义通常放模块或头文件中。跨模块边界时,map 往往更容易演进。
06 · 自己改一次
合上答案,动手
增加 set_pages/2,返回页数更新后的 record。
练习起点
set_pages(Book, Pages) ->
Book#book{____ = ____}.目标结果: 传入 120 时,新 record 的页数为 120。
卡住了,再看提示
字段名是 pages,新值变量是 Pages。
运行过以后,再看一种答案
一种答案
%% record 更新也返回新 term
set_pages(Book, Pages) ->
Book#book{pages = Pages}.想一想:record 是否像 map 一样在运行时保存字段名?
不是。record 主要在编译时展开成 tuple;运行时值本身不携带这些字段名。
带走
记住三句
- 1
模块属性服务编译器。
- 2
record 给固定 tuple 布局加字段名。
- 3
对外 API 不应轻易暴露 record 布局。
本课结束代码也跑过一次,就把这一课收好。