Erlang语言入门到入土- 入门教程
一、erlang基本语法(Erlang/OTP 中文手册)
一、基本数据类型
1、numbers数字运算法则
1> 2 + 15. %% 加法
17
2> 49 * 100. %% 乘法
4900
3> 1892 - 1472. %% 减法
420
4> 5 / 2. %% 最常用的浮点数除法
2.5
5> 5 div 2. %% div 是整除
2
6> 5 rem 2. %% rem 是取余运算
1
%% 数字前面可以用 ‘#’ 来标注其 ‘Base’
%% 语法:Base#Value %% 默认的 Base 10 …
%% 从其他进制转为十进制
10> 2#101010. %% 2 进制的 101010
42
11> 8#0677. %% 8 进制的 0677
447
12> 16#AE. %% 16 进制的 AE
174
2、Boolean布尔数据类型(与/或/非)
原子(atom)类型的 true 和 false 两个值,被用作布尔处理。
1> true and false. %% 逻辑 并
false
2> false or true. %% 逻辑 或
true
3> true xor false. %% 逻辑 异或
true
4> not false. %% 逻辑 非
true
5> not (true and true).
false
还有两个与 and 和 or 类似的操作:andalso和 orelse。区别是 and 和 or 不论左边的运算结果是真还是假,都会执行右边的操作。而 andalso 和 orelse是短路的,意味着右边的运算不一定会执行。
3、比较
6> 5 =:= 5. %% =:= 是"严格相等"运算符,== "是大概相等"
true
7> 1 =:= 0.
false
8> 1 =/= 0. %% =/= 是"严格不等"运算符,/= "是相差很多"
true
9> 5 =:= 5.0.
false
10> 5 == 5.0.
true
11> 5 /= 5.0.
false
一般如果懒得纠结太多,用 =:= 和 =/= 就可以了。
12> 1 < 2.
true
13> 1 < 1.
false
14> 1 >= 1. %% 大于等于
true
15> 1 =< 1. %% 注意这个 "小于等于" 的写法,= 在前面。因为 => 还有其他的用处。。
true
17> 0 == false. %% 数字和 atom 类型是不相等的
false
18> 1 < false.
true
虽然不同的类型之间可以比较,也有个对应的顺序,但一般情况用不到的:
number < atom < reference < fun < port < pid < tuple < list < bit string
4、模块和函数
1)、Erlang 里代码是用 Module 组织的。一个 Module 包含了一组功能相近的函数。用一个函数的时候,要这么调用:Module:Function(arg1, arg2)。
或者你先 import 某个 Module 里的函数,然后用省略Module名的方式调用:Function(arg1, arg2)。
2)、Module 可也提供代码管理的作用,加载一个 Module 到 Erlang VM就加载了那个 Module 里的所有代码,然后你想热更新代码的话,直接更新这个 Module 就行了。
示例1: 实现将数值翻倍
以一个目录下面新建一个文件名为tut.erl,输入以下代码
-module(tut).
-export([double/1]).
double(X)->
X *2.
在命令窗口输入以下代码
➜ erlang pwd
/Users/Macx/Public/erlang
➜ erlang c(tut). %要在不是erlang shell下才能去执行c(tut).编译文件会报错
zsh: no matches found: c(tut).
➜ erlang erl %要在erlang shell下才能去执行c(tut).编译文件
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.3.1 (abort with ^G)
1> c(tut).
{ok,tut}
2> tut:double(3).
%编译完成之后,可以用module:function 来调用方法
6
3>
示例2:计算一个数的阶乘,如:4的阶乘为 4 * 3 * 2 * 2 = 24
新建一个tut1.erl文件,代码如下:
-module(tut1).
-export([fac/1]).
fac(1) ->
1;
%以分号结束的,这也就表示后面还有 fac 函数的更多内容
fac(N) ->
N * fac(N -1).
%N 的阶乘为 N 乘以 N-1 的阶乘
在命令行中输入如下;
➜ erlang erl
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.3.1 (abort with ^G)
1> c(tut1).
{ok,tut1}
2>
2>
2> tut1:fac(4).****
24
对tut1.erl进行扩展
(Erlang 函数也可以有多个参数,实现一个函数完成两个数相乘)
修改tut1.erl如下
-module(tut1).
-export([fac/1,mult/2]).
fac(1) ->
1;
fac(N) ->
N * fac(N -1).
mult(X,Y) ->
X * Y.
在命令窗口输入如下:
➜ erlang erl
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.3.1 (abort with ^G)
1> c(tut1).
{ok,tut1}
2> tut1:m
module_info/0 module_info/1 mult/2
2> tut1:mult(2,3).
6
3>
5、内建函数BIF
erlang module 里的函数叫做 BIF.(内建函数)
示例:erlang 自带的Module(BIP)
45> erlang:element(2,{a,b,c}).
b
46> element(2,{a,b,c}).
b
48> lists:seq(1,4).
[1,2,3,4]
49> seq(1,4).
** exception error: undefined shell command seq/2
50> %上面的例子里,你能直接用 erlang Module 里的 element/2 函数,是因为 erlang 里的常用函数会被 潜在的 import 过来。其他的 Module 比如 lists 不会.
内置函数示例:
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.3.1 (abort with ^G)
1> trunc(5.6).
%就近取整
5
2> round(5.6).
%四舍五入
6
3> length([1,2,3,4]).
%列表长度
4
4> float(5).
%浮点数
5.0
5> is_atom(hello).
%是否为原子
true
6> is_atom("hello").
false
7> is_tuple({pairs,{c,30}}).
%是否为元组
true
8> is_tuple([pairs,{c,30}]).
false
9>
10> atom_to_list(hello).
%原子转为字符串
"hello"
11> list_to_atom("goodbay").
%字符串转为原子
goodbay
12> integer_to_list(22).
%整型转为列表
"22"
6、原子类型
原子类型是 Erlang 语言中另一种数据类型。以小写字母开头的名称是符号常量,称为原子。
-module(tut2).
-export([convert/2]).
%完成英寸与厘米之间的相互转换
%完成厘米转为英寸
convert(M,inch) ->
M / 2.54;
%%完成英寸转为厘米
convert(M, centimeter) ->
M * 2.54.
在命令窗口中如下:
%编译:
20> c(tut2).
{ok,tut2}
%测试:
21> tut2:convert(3,inch).
1.1811023622047243
22> tut2:convert(3,centimeter).
7.62
23> tut2:convert(3,other).
%Erlang 系统找不到匹配的子句,所以返回了错误消息 function_clause
** exception error: no function clause matching tut2:convert(3,centimeter4567) (tut2.erl, line 4)
24>
7、元组
上一示例中
tut2.convert(3,inch)
这是意味着 3 本身已经是英寸表示了呢?还是指将 3 厘米转换成英寸呢? Erlang 提供了将某些元素分成组并用以更易于理解的方式表示的机制。它就是元组。一个元组由花括号括起来的。所以,{inch,3} 指的就是 3 英寸,而 {centimeter, 5} 指的就是 5 厘米。接下来,我们将重写厘米与英寸之间的转换程序。将下面的代码输入到文件 tut3.erl 文件中
-module(tut3).
-export([convert_length/1]).
convert_length({centimeter, X}) ->
{inch, X / 2.54};
convert_length({inch, Y}) ->
{centimeter, Y * 2.54}.
在命令窗口
7> tut3:convert_length({inch,5}).
{centimeter,12.7}
8> tut3:convert_length(tut3:convert_length({inch,5}).
%%少输了一个括号导致报错
* 1: syntax error before: '.'
8> tut3:convert_length(tut3:convert_length({inch,5})).
{inch,5.0}
9>
8、列表
虽然元组可以将数据组成一组,但是我们也需要表示数据列表。 Erlang中的列表由方括号括起来表示。
示例1:世界上不同城市的温度列表就可以表示为:
1> [{moscow, {c, -10}},{cape_town,{f,70}},{stockholm,{c,-14}}]
1> .
[{moscow,{c,-10}},{cape_town,{f,70}},{stockholm,{c,-14}}]
2>
示例2:使用 “|” 查看部分列表
2> [First | TheRest]=[1,2,3,4].
[1,2,3,4]
%每间隔一个| 对应一个元素
3> First.
1
4> TheRest.
[2,3,4]
5>
示例3:使用“|” 对应多个元素
5> [E1, E2 | R ] = [1,2,3,4,5,6,7].
[1,2,3,4,5,6,7]
6> E1.
1
7> E2.
2
8> R.
[3,4,5,6,7]
9>
示例4:取值超过列表中元素的总数
10> [A, B| C]= [1, 2].
[1,2]
11> A.
1
12> B.
2
13> C.
[]
%取不到值时会返回一个空的列表
14>
示例5:获得一个列表的长度,
新建一个tut4.erl文件,代码如下:
-module(tut4).
-export([list_length/1]).
list_length([]) ->
0;
list_length([First | Rest]) ->
1 + list_length(Rest).
在命令窗口
%编译
1> c(tut4).
tut4.erl:8: Warning: variable 'First' is unused
{ok,tut4}
%运行
3> tut4:list_length([1,2,3,4]).
4
4>
示例6:在 Erlang 中字符串可以用 Unicode 字符的列表表示
4> [97,98,99].
"abc"
5>
9、if 以case
语法格式
if
Condition 1 ->
Action 1;
Condition 2 ->
Action 2;
Condition 3 ->
Action 3;
Condition 4 ->
Action 4
end
注意,在 end 之前没有 “;”。条件(Condidtion)的工作方式与 guard 一样,即测试并返回成功或者失败。
示例1:
-module(tut9).
-export([test_if/2]).
test_if(A, B) ->
if
A == 5 ->
io:format("A == 5~n",[]),
a_equals_5;
B == 6 ->
io:format("B == 6~n",[]),
b_equals_6;
A == 2, B == 3 ->
io:format("A == 2, B == 3~n",[]),
a_equals_2_and_b_equals_3;
A == 1; B == 7 ->
io:format("A == 1; B== 7~n",[]),
a_equals_1_or_b_equals_7
end.
在命令窗口
%运行
9> tut9:test_if(5,[]).
A == 5
a_equals_5
10> tut9:test_if([],6).
B == 6
b_equals_6
11> tut9:test_if(2,3).
A == 2, B == 3
a_equals_2_b_equals_3
12> tut9:test_if(1,[]).
A == 1; B== 7
a_equals_1_or_b_equals_7
13> tut9:test_if([],7).
A == 1; B== 7
a_equals_1_or_b_equals_7
14> tut9:test_if([],[]).
** exception error: no true branch found when evaluating an if expression
in function tut9:test_if/2 (tut9.erl, line 6)
%%tut9:test_if([],[]) 使得所有测试条件都失败,这将导致产生一个 if_clause 运行时错误
15>
示例2:输入年份得到指定某月的天数
新建tut11.erl 代码如下:
-module(tut11).
-export([month_length/2]).
month_length(Year,Month) ->
%% 被 400 整除的为闰年。
%% 被 100 整除但不能被 400 整除的不是闰年。
%% 被 4 整除但不能被 100 整除的为闰年。
Leap = if
trunc(Year / 400) * 400 == Year ->
%Year取整除400 再乘400 等于Year,说明能被400整除
leap;
trunc(Year / 100) * 100 == Year ->
not_leap;
trunc(Year / 4) * 4 == Year ->
leap;
true ->
not_leap
end,
case Month of
apr -> 30;%四月
jun -> 30;%六月
sept -> 30;%九月
nov -> 30;%十一月
feb when Leap == leap -> 29;%闰年二月
feb -> 28;%平年二月
jan -> 31;%一月
mar -> 31;%三月
may -> 31;%五月
jul -> 31;%七月
aug -> 31;%八月
oct -> 31;
%十月
dec -> 31
%十二月
end.
在命令窗口
%编译
21> c(tut11).
{ok,tut11}
22> tut11:month_length(2004,feb).
29
23> tut11:month_length(2003,feb).
28
24> tut11:month_length(1947,feb).
28
25> tut11:month_length(17,feb).
28
10、映射(map)
使用映射组的方式是在首次定义某个键时总是使用Key => Val,而在修改具体某个键的值时都使用Key := Val, 键和值可以是任何有效的Erlang数据类型
注:map 要更新到最新的erl版本才能运行(R17版本的erlang 才添加map,所以致少要升到R17的版本)
%%Erlang R15B03 版本报错
➜ Cellar erl
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.3.1 (abort with ^G)
1> #{name =>"yzf" ,age=>26}.
* 1: syntax error before: '{'
1>
1>
在命令窗口
%%Erlang/OTP 19 版本可以执行成功
[root@iz7mrdaho3jf9lz otp_src_19.1]# erl
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.1 (abort with ^G)
1> #{age => 26,name => "yzf"}.
#{age => 26,name => "yzf"}
1)、创建映射组
1> #{name => "youname", age=> 26}.
#{age => 26,name => "youname"}
%输出
2> #{}.
#{}
3>
2)、更新映射组
% => 用于创建或更新一个映射
13> Me = #{name =>"zyf",age =>26}.
#{age => 26,name => "zyf"}
14> NewMe = Me#{age => 20}.
#{age => 20,name => "zyf"}
15> Me.
#{age => 26,name => "zyf"}
16>
16> #{name =>"zyf",age =>26}#{age =>27}.
#{age => 27,name => "zyf"}
17>
在命令窗口
% 使用 :=,它只能用来更新映射,而不能创建新的映射,如果键不存在,就会抛出一个 badarg 异常
1> Me = #{name =>"zyf",age =>26}.
#{age => 26,name => "zyf"}
2> Me#{age := 27}.
#{age => 27,name => "zyf"}
3> Me#{aeg := 27}.
** exception error: {badkey,aeg}
in function maps:update/3
called as maps:update(aeg,27,#{age => 26,name => "zyf"})
in call from erl_eval:'-expr/5-fun-0-'/2 (erl_eval.erl, line 255)
in call from lists:foldl/3 (lists.erl, line 1263)
4>
3)、map参数匹配
%部分匹配:
%只取出一个参数的映射
1> Me = #{age=> 19,name=>"zyfa"}.
#{age => 19,name => "zyfa"}
2> #{age := NewAge}=Me.
%重新匹配
#{age => 19,name => "zyfa"}
3> NewAge .
19
4>
4> #{age => NewAge2}=Me.
* 2: illegal pattern
%用=>符号去匹配会报错
5>
Erlang 中的 maps 模块用于操作映射组
4)、映射组的创建及属性
%创建
6> maps:new().
#{}
%新建一个Me的映射
7> Me =#{age=>19,name=>"zyf"}.
#{age => 19,name => "zyf"}
%查询映射的所有键
8> maps:keys(Me).
[age,name]
9>
%判断是否存在键
%存在时
10> maps:is_key(age,Me).
true
%不存在时
11> maps:is_key(age111,Me).
false
%查询出Me里面的所有值
12> maps:values(Me).
[19,"zyf"]
%查询映射里面的数量
13> maps:size(Me).
2
% erlang:map_size/1 此函数可以用于 Guard,maps 模块内部也是使用此函数的
14> map_size(Me).
2
15>
5)、映射的增加、删除、获取
% 获取映射里面的 age key 的值,找不到key时会报错
16> maps:get(age,Me).
19
% 查不到age123这个key的值,会报异常提示
17> maps:get(age123,Me).
** exception error: {badkey,age123}
in function maps:get/2
called as maps:get(age123,#{age => 19,name => "zyf"})
18>
% maps:get/3 在键不存在时会返回第三个参数的值
18> maps:get(age123,Me,18).
18
% 添加参数到映射里面,原映射组并不会改变
19> maps:put(gender,male,Me).
#{age => 19,gender => male,name => "zyf"}
20> Me.
#{age => 19,name => "zyf"}
% 用于更新映射,类似于 :=,键不存在时会抛出 badarg 异常
21>
21> maps:update(age,20,Me).
#{age => 20,name => "zyf"}
22> maps:update(age321,20,Me).
** exception error: {badkey,age321}
in function maps:update/3
called as maps:update(age321,20,#{age => 19,name => "zyf"})
23>
% 删除一个映射,键不存在时相当于什么都没做,不会抛出异常
23> maps:remove(age,Me).
#{name => "zyf"}
24>
% 查找键的值,键不存在时返回 error
24> maps:find(age,Me).
{ok,19}
25> Me.
#{age => 19,name => "zyf"}
26> maps:find(age3,Me).
error
27>
6)、映射组的归并
% 新建一个Me映射
1> Me=#{age=> 10,name=>"zyfaa"}.
#{age => 10,name => "zyfaa"}
%新建一个Me1映射
2> Me2=#{height=>173}.
#{height => 173}
%将Me、Me2合并 height键会合并到新的映射里面
3> maps:merge(Me,Me2).
#{age => 10,height => 173,name => "zyfaa"}
%新建一个Me3映射,age为39
4> Me3=#{age=>39}.
#{age => 39}
%将Me、Me3合并 age会更新到最新的值
5> maps:merge(Me,Me3).
#{age => 39,name => "zyfaa"}
7)、映射组与列表之间的转换
5> Me=#{age=> 10,name=>"zyfaa"}.
#{age => 10,name => "zyfaa"}
% 返回映射对应的列表
6> maps:to_list(Me).
[{age,10},{name,"zyfaa"}]
%从列表构建一个空的映射组
7> maps:from_list([]).
#{}
8>
%从列表构建一个新的映射组
9> maps:from_list([{name,"zfsfd"},{age,33}]).
#{age => 33,name => "zfsfd"}
10> Me21 = maps:from_list([{name,"zfsfd"},{age,33}]).
#{age => 33,name => "zfsfd"}
11>
8)、映射组的遍历
% 对映射组的每对映射执行操作
% X, Y 分别为一对映射的键和值
11> Me21 = maps:from_list([{name,"zfsfd"},{age,33}]).
#{age => 33,name => "zfsfd"}
12> maps:map(fun (X, Y) -> io:format("~p => ~p~n",[X, Y]) end,Me21).
age => 33
name => "zfsfd"
#{age => ok,name => ok}
13>
% X, Y 分别为一对映射的键和值,V 为上一次迭代的结果,0 为迭代的初始值
% 这里简单的用于每次迭代时值加 1,结果就是映射组的映射数量
13> maps:fold(fun(X,Y,V) ->V + 1 end,0,Me).
2
9)、映射组中映射的选取
1、返回第一个参数中指定的键的映射组成的映射组
14> maps:with([],Me).
#{}
15> maps:with([name],Me).
#{name => "zyfaa"}
16> maps:with([age],Me).
#{age => 10}
17>
17> maps:with([age22],Me).
#{}
2、返回键不再第一个参数的列表中的映射组成的映射组
18> maps:without([],Me).
#{age => 10,name => "zyfaa"}
19>
19> maps:without([age],Me).
#{name => "zyfaa"}
20> maps:without([age,name],Me).
#{}
% 键也可以不存在
21> maps:without([age,name234],Me).
#{name => "zyfaa"}
22>
注意
值得一提的是 maps 模块中的若干函数,比如 map, fold, with 和 without 都是使用 maps:to_list/1 转到列表,然后使用 lists 模块的工具处理,然后使用 maps:from_list/1 转回到映射组的。
11、记录(record)
记录其实就是元组的另一种形式。通过使用记录,可以给元组里的各个元素关联一个名称。
何时使用:
当你可以用一些预先确定且数量固定的原子来表示数据时;
当记录里的元素数量和元素名称不会随时间而改变时;
当存储空间是个问题时,典型的案例是你有一大堆元组,并且每个元组都有相同的结构
新建一个文件 record.erl,代码如下:
-module(record).
% 定义一个记录
-record(book,{author, bookname, chapters = 0}).
在命令窗口执行
% 编译文件
1> c(record).
{ok,record}
2>
%在Erlang的shell中,如果想创建record的实例,必须先读取记录的定义,使用命令rr(read record)
3> rr("record.erl").
[book]
% 创建记录
4> Shuihu = #book{author ="edit", bookname= "haliboke"}.
#book{author = "edit",bookname = "haliboke",chapters = 0}
% 更新记录
6> Shuihu2 = Shuihu#book{chapters = 36}.
#book{author = "edit",bookname = "haliboke",chapters = 36}
% 提取记录.
7> #book{author = Author1 , bookname= Bookname,chapters = Pirse} = Shuihu.
#book{author = "edit",bookname = "haliboke",chapters = 0}
8> Author1.
"edit"
9> Bookname.
"haliboke"
10> pirse.
pirse
11> Pirse.
0
12>
12、Guards与变量的作用域
示例:在列表中找出最大的值,新建一个tut6.erl文件如下:
-module(tut6).
-export([list_max/1]).
list_max([Head|Rest]) ->
list_max(Rest,Head).
list_max([], Res) ->
Res;
%when 用在函数的 -> 前时是一个特别的的单词,
%它表示只有测试条件为真时才会用到函数的这一部分。
%这种类型的测试被称这为 guard 如果 guard 为假 (即 guard 测试失败),
%则跳过此部分而尝试使用函数的后面一部
list_max([Head|Rest],Result_so_far) when Head > Result_so_far ->
list_max(Rest,Head);
%每个变量在其作用域内只能被赋值一次。
%从上面的例子中也可以看到,Result_so_far 却被赋值多次。
%这是因为,每次调用一次 list_max/2 函数都会创建一个新的作用域。
%在每个不同的作用域中,Result_so_far 都被当作完全不同的变量。
list_max([_Head|Rest],Result_so_far) ->
list_max(Rest,Result_so_far).
在命令窗口执行
%编译
3> c(tut6).
{ok,tut6}
%调用方法,找出列表中最大的值
4> tut6:list_max([1,2,3,4,5,33,4,5,6,7,8]).
33
5>
1)、guard
when 用在函数的 -> 前时是一个特别的的单词,它表示只有测试条件为真时才会用到函数的这一部分,这种类型的测试被称这为 guard。
guard 中的操作符还包括:
< 小于
> 大于
== 等于
>= 大于或等于
=< 小于或等于
/= 不等于
2)、作用域
每个变量在其作用域内只能被赋值一次。从上面的例子中也可以看到,Result_so_far 却被赋值多次。 这是因为,每次调用一次 list_max/2 函数都会创建一个新的作用域。在每个不同的作用域中,Result_so_far 都被当作完全不同的变量。
13、匹配操作符
5> {X,Y} = {paris,{f,28}}.
{paris,{f,28}}
6> X.
paris
7> Y.
{f,28}
8>
14、高阶函数(Fun)
在shell中定义了一个数值翻倍的函数
1> Xf = fun (X) -> X * 2 end.
#Fun<erl_eval.6.52032458>
2> Xf(5).
10
3>
操作列表处理函数 foreach 、 map
foreach(Fun,[First|Rest]).
Fun(First),
foreach(Fun,Rest);
foreach(Fun,[])->
ok.
map(Fun, [First|Rest]) ->
[Fun(First)|map(Fun,Rest)];
map(Fun,[])->
[].
在 shell 中使用 map 的 Xf 函数生成一个新的列表:
1> Xf = fun (X) -> X * 2 end.
#Fun<erl_eval.6.52032458>
2> Xf(5).
10
3>
3>
3> lists:map(Xf,[1,2,3,4]).
[2,4,6,8]
4>
输出一组城市的温度值
4> Print_City = fun({City,{X,Temp}}) -> io:format("~-15w ~w ~w~n",[City, X, Temp]) end.
#Fun<erl_eval.6.52032458>
6> lists:foreach(Print_City,[{moscow,{c, -10}},{cape_town, {f, 70}},{stockholm, {c, -4}},{paris,{f, 28}},{londom,{f,36}}]).
moscow c -10
cape_town f 70
stockholm c -4
paris f 28
londom f 36
ok
7>
遍历城市温度列表并将每个温度值都转换为摄氏温度表示
-module(tut13).
-export([convert_list_to_c/1]).
convert_to_c({Name,{f, Temp}}) ->
{Name, {c, trunc((Temp - 32 ) * 5 / 9)}};
convert_to_c({Name, {c, Temp}}) ->
{Name, {c, Temp}}.
convert_list_to_c(List) ->
lists:map(fun convert_to_c/1,List).
在命令窗口执行
%编译
8> c(tut13).
{ok,tut13}
9>
9> tut13:convert_list_to_c([{moscow,{c,-10}}]).
[{moscow,{c,-10}}]
11>
11> tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},
11> {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
[{moscow,{c,-10}},
{cape_town,{c,21}},
{stockholm,{c,-4}},
{paris,{c,-2}},
{london,{c,2}}]
15、匿名函数
fun({_,{c,Temp1}},{_,{c, Temp2}})-> Temp1 < Temp2 end.
这儿用到了匿名变量 “_” 的概念。匿名变量常用于忽略一个获得的变量值的场景下。当然,它也可以用到其它的场景中,而不仅仅是在高阶函数这儿。
Temp1 < Temp2 说明如果 Temp1 比 Temp2 小,则返回 true。
二、erlang shell中运行文件中的方法
1、Erlang Shell 是一个快速尝试新想法的地方,但我们真正的代码是要写到文件里,然后参与编译的。
在一个目录(我这边为/Users/Macx/Public/erlang这个目录)下面新建一个text.erl的文件
在文件的第一行, 用 -module(text) 来声明你的 module name。注意跟 java 类似,module 名要跟文件名一样。
然后你在你的 module 里写你的函数,text.erl代码如下
-module(text).
-export([add/2,add/3]).
%% export 是导出语法,指定导出 add/2, add/3 函数。没导出的函数在 Module 外是无法访问的。
add(A,B) ->
A + B.
add(A,B,C) ->
A + B + C.
在 shell中的操作如下:
➜ erlang pwd
%查看当前的目录路径;
/Users/Macx/Public/erlang
➜ erlang ll
%查看当前的目录路径下的文件;
-rw-r--r--@ 1 Macxstaff 0B 6 12 10:39 text.erl
➜ erlang mkdir -p ./ebin
%在当前路径下建一个ebin的文件目录
➜ erlang erlc -o ebin text.erl
%用erlc编译文件,并把文件放到ebin下面
➜ erlang ll ebin %查看ebin 下面是否有文件
total 8
-rw-r--r-- 1 Macxstaff 580B 6 12 10:42 text.beam
➜ erlang erl -pa ./ebin
%erl -pa 参数的意思是 Path Add, 添加目录到 erlang 的 beam 文件查找目录列表里。
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.3.1 (abort with ^G)
1> pwd
1> .
pwd
2> text(1,4).
%%直接调用方法会报错找不到方法
** exception error: undefined shell command text/2
3> text:add(1,4).
%添加模块名加方法名后可以正常调到方法
5
4> text:add(1,4,8).
13
5>
本作品采用《CC 协议》,转载必须注明作者和本文链接