Elixir 从零 · 第 04 课(展开目录)
从旧 list 生成新 list
先绑定一列值,再用 for comprehension 产生新 list。
保留旧 list,产生新 list
先看输入 list,再看 comprehension 产生的结果。
# numbers 指向原来的 list
numbers = [1, 2, 3]
# 每次结果会被收集到新 list
plus_one =
for number <- numbers do
number + 1
end
{numbers, plus_one}- 得到
{[1, 2, 3], [2, 3, 4]}。 numbers仍是[1, 2, 3]。plus_one指向新 list[2, 3, 4]。
从第一行往下读
numbers = [1, 2, 3]把名字绑定到原 list。number <- numbers从左到右取出 1、2、3,当前值暂时叫number。- 块里的
number + 1每次产生一个新数字,for把它们收集成[2, 3, 4]。 - 整个过程没有修改
numbers,所以 tuple 中仍能看到原 list。 - IEx 只负责把结果展示出来。看到
~c"..."时,可以逐个对照字符码点;值依旧是整数 list。
符号不是暗号
=这里先读作“让左边名字指向右边的值”。下一课会看到它也是匹配运算符。
<-从右边集合依次取一个值,交给左边名字。
for ... do ... end运行 comprehension,并把每次结果收集成新 list。
+把左右两个数字相加,返回一个新数字。
~c"4L["charlist 写法;它与 [52, 76, 91] 是同一个值。
把名字和意思对上
绑定
让一个名字指向某个值,如 count = 3。
不可变
已经存在的值不会被原地改写。计算会产生新值。
comprehension
从集合依次取值,计算后收集成新集合;它不会修改原集合。
charlist 显示
charlist 本质上仍是整数 list。整数都能解释成可打印字符时,IEx 会优先用 ~c"..." 显示。
这些写法为什么有用
名字让代码容易读。numbers = [1, 2, 3] 可以读成“名字 numbers 现在指向这列数字”。
Elixir 的数据不会被原地改掉。对 list 做计算会产生新 list,原来的 list 仍保持不变。
for value <- list do ... end 叫 comprehension。它从 list 依次取值,用块里的表达式产生新值,最后收集成新 list。
练习里的 52、76、91 恰好也是字符 4、L、[ 的 Unicode 码点。因此 IEx 可能把同一个整数 list 显示成 ~c"4L["。这只是显示方式,不是数据变成了字符串。
单独输入空行或只有 # 注释的一行时,IEx 会回显 nil。它只表示这一行没有产生有用结果,不会被放进 scores 或 raised。
合上答案,动手
把分数 [52, 76, 91] 每项加 5,同时保留原 list。
# 原始分数
scores = [52, 76, 91]
# 补上取值符号和每次产生的新值
raised =
for score ____ scores do
____
end
{scores, raised}目标结果: 逻辑结果是 {[52, 76, 91], [57, 81, 96]}。IEx 也可能显示成 {~c"4L[", ~c"9Q"},两种写法表示完全相同的两个整数 list。粘贴时夹在中间的 nil` 只来自空行或注释。
卡住了,再看提示
取值使用 <-;块里写 score + 5。若想强制按数字显示,可先单独运行 IEx.configure(inspect: [charlists: :as_lists])。
运行过以后,再看一种答案
# 原始 list 保持不变
scores = [52, 76, 91]
# comprehension 收集每次加 5 的结果
raised =
for score <- scores do
score + 5
end
{scores, raised}想一想:IEx 显示 `scores` 为 `~c"4L["`,是否说明它已经变成文字?
没有。~c"4L[" == [52, 76, 91] 的结果是 true。charlist 就是整数 list 的另一种显示法;for 也没有修改原来的 scores。
记住三句
- 1
名字指向值,方便后面的代码使用。
- 2
<-从集合中依次取值。 - 3
comprehension 产生新 list,不会原地修改旧 list。
- 4
~c"..."可能只是 IEx 对整数 list 的显示选择。