元组tuple
元组,用于保存固定数量的元素。创建元组的方法就是用大括号{}
把想要表达的值括起来,并用逗号分隔他们。例如,表示某人的年龄:{Jack, 18}
Erlang没有类型声明,创建一个坐标点,只需:
P = {
10, 15}.
这样就创建了一个元祖并绑定在变量P上。
由于元组里的字段没有名字,为了记住该元组的用途,通常会写成以下方式:{point, 10, 15}
,这样提高使程序的可理解性。
元组是可以嵌套的,例如:
1> Person = {
person, {
name, Jack}, {
age, 18}}.
{
person, {
name, Jack}, {
age, 18}}
1. 创建元组
元组会在声明他们的时候自动创建,不再使用时被销毁。如果在构建新的元组时用到变量,那么新的元组会共享该变量所引用的数据结构的值。例如,
2> F = {
firstname, jack}.
{
firstname, jack}
3> L = {
lastname, chan}.
{
lastname, chan}
4> p = {
person, F, L}.
{
person, {
firstname, jack}, {
lastname, chan}}
2. 提取元组的值
通过使用模式匹配操作符=
从元组中提取一些值。
1> Point = {
point,10,15}.
{
point,10,15}
2> {
point,X,Y} = Point.
{
point,10,15}
3> X.
10
4> Y.
15
注意:等号两侧的元组必须要有相同数量的元素,而且两侧的对应元素必须绑定为相同的值。如:
5> Point1 = {
point,5,5}.
{
point,5,5}
6> {
point,C,C} = Point1.
{
point,5,5}
7> C.
5
如果有一个复杂的元组,就可以编写一个与该元组形状(结构)相同的模式,并在待提取值的位置加入未绑定的变量来提取该值。
Eshell V8.3 (abort with ^G)
1> Person = {
person,{
name,jack,chan},{
age,18}}.
{
person,{
name,jack,chan},{
age,18}}
2> {
_, {
_, Who, _}, _} = Person.
{
person,{
name,jack,chan},{
age,18}}
3> Who.
jack
其中,"_
“被称为匿名变量。与正规变量不同,同一模式里的多个”_
"不必绑定相同的值。
列表list
列表,被用来存放任意数量的事物。创建列表的方法是用中括号[]
把列表元素括起来,并用逗号分隔开。
列表的第一个元素称为列表头head
,其余部分称为列表尾tail
。例如:列表[1, 2, 3, 4, 5]
的列表头为整数1,[2, 3, 4, 5]
为列表尾。
1. 定义列表
如果T是一个列表,那么[H | T]
也是一个列表,他的头是H
,尾是T
。竖线 |
把列表的头与尾分隔开。[]
是一个空列表。
无论何时,只要用[... | T]
表示一个列表,就应该确保T
是列表。此时称为格式正确的列表,否则称为不正确的列表。
可以给T
的开头添加不止一个元素,写法是[E1,E2,...,EN | T]
1> T = [{
apple, 10}, {
pear, 5}].
[{
apple, 10}, {
pear, 5}]
2> T1 = [{
orange, 15} | T].
[{
orange, 15}, {
apple, 10}, {
pear, 5}]
2. 提取列表元素
通过模式匹配操作来提取某个列表里的元素。如果有一个列表L
,那么表达式[X | Y] = L
会提取列表头作为X
,列表尾作为Y
。
3> [B1 | B2] = T1.
[{
orange, 15}, {
apple, 10}, {
pear, 5}]
4> B1.
{
orange, 15}
5> B2.
[{
apple, 10}, {
pear, 5}]
3. 列表处理注意点
Eshell V8.3 (abort with ^G)
1> A = [[1,2],[2,3],[3,4]].
[[1,2],[2,3],[3,4]]
2> [B,C|T] = A.
[[1,2],[2,3],[3,4]]
3> B.
[1,2]
4> C.
[2,3]
5> T.
[[3,4]]
6> D = [1,2,3].
[1,2,3]
7> E = [3,4,5,6].
[3,4,5,6]
8> F = [D|E].
[[1,2,3],3,4,5,6]
9> G = D ++ E.
[1,2,3,3,4,5,6]
4. 列表推导
[F(X) || X <- L]
标记表示“由F(X)
组成的列表(X
从列表L
中提取)”。[2 *X || X <- L]
表示“由2 * X
组成的列表”。
以下实现将列表中每一项的数字加倍:
1> Buy = [{
apples,1},{
pears,2},{
newspaper,1}].
[{
apples,1},{
pears,2},{
newspaper,1}]
2> [{
Name,2*Num} || {
Name,Num} <- Buy].
[{
apples,2},{
pears,4},{
newspaper,2}]
注意,||
右侧的元组{Name, Number}
是一个模式,用于匹配Buy
中的各个元素。左侧的元组{Name, 2*Number}
是一个构造器
列表推导最常规的形式是下面这种表达式:
[X || Qualifier1, Qualifier2, ...]
X
是任意一条表达式,后面的限定符(Qualifier)可以是生成器、位串生成器或过滤器。
- 生成器(generator)的写法是
Pattern <- ListExpr
,其中的ListExp
必须是一个能够得出列表的表达式。 - 位串(bitstring)生成器的写法是
BitStringPattern <= BitStringExpr
,其中的BitStringExpr
必须是一个能够得出位串的表达式。 - 过滤器(filter)既可以是判断函数(即返回
true
或false
的函数),也可以是布尔表达式。
5. 列表常用函数
-
lists:keyfind(Key, N, TupleList) -> Tuple | false
在元组列表TupleList
中搜索第n
个元素与Key
相等的元组。如果找到这样的元组,则返回元组,否则返回false
。 -
lists:keystore(Key, N, TupleList1, NewTuple) -> TupleList2
返回TupleList1
的副本,其中第n
个元素等于Key
的元组T
的第一个出现位置将被替换为NewTuple
,如果没有这样的元组T
,则返回TupleList1
的副本,并将[NewTuple]
附加到末尾。 -
lists:keysort(N, TupleList1) -> TupleList2
返回一个包含列表TupleList1
的已排序元素的列表。排序是在元组的第n
个元素上执行的。 -
lists:sort(Fun, List1) -> List2
根据排序函数Fun
,返回一个包含List1
排序元素的列表。 -
lists:usort(List1) -> List2
返回一个包含List1
的已排序元素的列表,并删除重复项。 -
lists:keymember(Key, N, TupleList) -> boolean()
如果TupleList
中有一个元组,其第n
个元素与Key
相等,则返回true
,否则返回false
。 -
lists:member(Elem, List) -> boolean()
如果Elem
在列表List
中,则返回true
,否则返回false
。 -
lists:sublist(List1, Len) -> List2
返回List1
的子列表,从位置1
开始,包含Len
个元素。当Len
超过列表的长度时,将返回整个列表。 -
lists:sublist(List1, Start, Len) -> List2
返回List1
的子列表,从位置Start
开始,包含Len
个元素。当Start+Len
超过列表的长度时,将返回整个列表。 -
lists:foldl(Fun, Acc0, List) -> Acc1
对列表的连续元素Elem
调用Fun(Elem,AccIn)
,从AccIn==Acc0
开始。Fun/2
必须返回一个新的累加器,它被传递给下一个调用。函数返回累加器的最终值。如果列表为空,则返回Acc0
。 -
lists:foldr(Fun, Acc0, List) -> Acc1
同foldl/3,但遍历元素顺序为从右到左。如下:
> P = fun(A, AccIn) -> io:format("~p ", [A]), AccIn end.
#Fun<erl_eval.12.2225172>
> lists:foldl(P, void, [1,2,3]).
1 2 3 void
> lists:foldr(P, void, [1,2,3]).
3 2 1 void
-
lists:any(Pred, List) -> boolean()
Pred = fun((Elem :: T) -> boolean())
List = [T]
T = term()
如果列表中至少一个元素Elem
使得Pred(Elem)
返回true
,则返回true
。 -
lists:all(Pred, List) -> boolean()
如果列表中所有元素Elem
都使得Pred(Elem)
返回true
,则返回true
。 -
lists:nthtail(N, list) -> Tail
返回从N+1开始一直到列表的结尾的子列表。 -
lists:nth(N, List) -> Elem
返回列表的第n个元素。 -
erlang:hd(List)
返回列表的头,即第一个元素。 -
lists:last(List) -> Elem
返回列表中的最后一个元素。 -
lists:flatmap(Fun, List1) -> List2
//Fun = fun((A) -> [B])
//List1 = [A]
//List2 = [B]
//A = B = term()
Takes a function from As to lists of Bs, and a list of As (List1) and produces a list of Bs by applying the function to every element in List1 and appending the resulting lists.
That is, flatmap behaves as if it had been defined as follows:
flatmap(Fun, List1) -> append(map(Fun, List1)).
Example:
> lists:flatmap(fun(X)->[X,X] end, [a,b,c]).
[a,a,b,b,c,c]
记录record
记录是元组的另一种形式,通过使用记录,可以给元组里的各个元素关联一个名称。
用记录声明命名元组里的元素,语法如下:
-record(Name, {
%%以下两个键带有默认值
key1 = Default1,
key2 = Default2,
...
%%下一行就相当于Key3 = Undefined
Key3,
...
}).
-record
不是一个shell命令,在shell里要使用rr
。记录声明只能在Erlang源代码模块里使用,不能用于shell。
Name
是记录名。Key1
,Key2
这些是记录中各个字段的名称,他们必须是原子。记录里的每个字段都可以带一个默认值,如果创建记录时没有指定某个字段值,就会使用默认值。
记录的定义既可以保存在Erlang源代码文件里,也可以由扩展名为.hrl
的文件保存,然后包含在Erlang源代码文件里。
文件包含是唯一能确保多个Erlang模块共享相同记录定义的方式。
%% records.hrl
-record(todo, {
status=reminder, who=jack, text}).
记录一旦定义,就可以创建该记录的实例了。
要在shell中创建实例,必须先把记录的定义读入shell。
1> rr("record.hrl").
[todo]
rr
是read records的缩写,即读取记录
1. 创建记录
2> #todo{
}.
#todo{
status = reminder,who = jack,text = undefined}
3> X1 = #todo{
status = urgent, text = "So urgent"}.
#todo{
status = urgent,who = jack,text = "So urgent"}
4> X2 = X1#todo{
status = done}.
#