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 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!