第二章 开始—2

2.7 浮点数

       让我们来做一些浮点数的运算:

1> 5/3.

1.66667

2> 4/2.

2.00000

3> 5 div 3.

1

4> 5 rem 3.

2

5> 4 div 2.

2

6> Pi = 3.14159.

3.14159

7> R = 5.

5

8> Pi * R * R.

78.5397

       不要在此感到困惑。在第一行结尾的数是整数3。表达式的结尾句号不是一个小数点。如果我想要一个小数点应该这样写3.0

       /”常常返回一个浮点数;由此,4/2的值是2.0000(在shell)。NM

NremM是用来进行整数除法和余数运算的;由此53153的余数是2

       浮点数必须在小数点后有至少一位的十进制数。当你使用“/”来使两整数相除时,结果是自动转化为浮点数的。

2.8 常量

       Erlang中,常量被用来表示不同非数值得常数。

       如果你以前列举过C和Java中的数据类型,你可能已经了解常量。

       C程序员对使用宏定义的格式很熟悉。典型的C程序将定义一系列的全局常量,这些常量包含在一个定义常量的文件中;例如;这可能是一个glob.h的文件包含的内容。

#define OP_READ 1

#define OP_WRITE 2

#define OP_SEEK 3

...

#define RET_SUCCESS 223

...

       典型的C代码使用宏定义可能如下所示:

#include "glob.h"

int ret;

ret = file_operation(OP_READ, buff);

if( ret == RET_SUCCESS ) { ... }

       在一个C程序中,这些常量的值并不感兴趣;他们在这里只是意味着他们是不同的,他们能够与等式比较。

       Erlang中,等效的表达可能是这样的:

Ret = file_operation(op_read, Buff),

if

       Ret == ret_success ->

              ...

       Erlang中,常量是全局的,这不需要使用宏定义或者是包括头文件。

       假设你想要写编写一段处理星期的程序。你怎样来在Erlang中表示星期,你可以使用常量星期一、星期二…..

       常量开始于小写字母,紧接着是一连串的字母或者是下划线或者是(@)符。例如:red, december, cat, meters, yards, joe@somehost, and a_long_name.

       常量能够以(‘)符来引用。使用引用的格式,我们创建的常量以大写字母打头(否则会被当成变量)或者是包括字符字母。例如:‘Monday’, Tuesday’,

’+’,  ’*’,  ’an atom with spaces’。你甚至可以不使用引号引用常量,所以‘a’的含意与a一样。

       常量的含义就是常值。所以如果你你所给的命令就是一个常量,Erlang shell中将在打印这个常量:

1> hello.

hello

       这可能有一些奇怪,当我们讨论常量的值或者是整数的值。但是因为Erlang是一个功能编程语言,每一个表达式必须有一个值。这些包括整数和常量,并且都是简单的表达式。

2.9 Tuples

       假设你想一系列复杂的元素组成一个整体。在这种情况下你使用Tuples。你可以通过将有用Tuples用括号围起来,用逗号分割这种方式来创建一个Tuples。所以,例如,如果你想表示某人的名字和身高,你可以这样使用{Joe1.82}。这就是一个Tuples包括一个常量和一个浮点数。

       Tuples类似于C中的结构体,不同点就是Tuples是无名的。在C中,指针变量P可能如下定义:

struct point {

int x;

int y;

} P;

       你可以使用点操作符得到结构体内部的变量。所以为了设置pointxy的值,你可以这样写:P.x = 10; P.y = 45;

       Erlang没有类型的声明,所以为了创建一个“point”,我们可以这样写:

P = {10, 45}

       这就创建了一个Tuples同时把它绑定到了变量P。和C不一样的是,Tuple没有名字。因为Tuple本身就含有两个整数,我们不得不记住他的用途。为了便于记忆,我们常常使用常量作为Tuple的第一个元素,这个常量描述了它代表的含义。所以我们写{point, 10, 45} 而不是 {10, 45},这使得程序易于理解。

       Tuples是易用的。假设我们想要表达某个人的一些事实—名字、身高、鞋大小和眼睛的颜色。我们可以这样做:

1> Person = {person,

                            {name, joe},

                            {height, 1.82},

                            {footsize, 42},

                            {eyecolour, brown}}.

注意:我们使用常量来定义域和(例如名字和眼睛的颜色)来给这个域一个值。

创建Tuples

       在我们声明时,自动创建Tuples;当我们不使用是将自动销毁。Erlang使用内存收集来回收所有的未用内存,所以我们不需要担心内存的回收。

       如果我们建立一个新的Tuple时使用一个变量,新的Tuple将会使用分享数据结构中的变量的值。这有一个例子:

2> F = {firstName, joe}.

{firstName,joe}

3> L = {lastName, armstrong}.

{lastName,armstrong}

4> P = {person, F, L}.

{person,{firstName,joe},{lastName,armstrong}}

       如果你试图创建一个包含未知变量的数据结构,你将会看到错误。所以在下一行,如果我们无奈试图使用变量没有定义的Q,得到以下的错误:

5> {true, Q, 23, Costs}.

** 1: variable 'Q' is unbound **

       这就意味着变量Q没有定义。

       Tuples中提取值

       早先,我们说=,就像一个赋值的声明,它不仅仅是一个赋值的声明还是一个格式匹配运算符。你想知道为什么为什么我们这么书生气。当然,它表明格式匹配时Erlang中的基础,他被用来做许多不同的工作。他被用来提取数据结构中的值,他还被用来在函数中控制循环,还有但你给进程发消息时,它负责将选择哪条消息是由平行的程序发出的。

       如果你想从一个Tuples中选出一些值,我们使用=操作符。

       让我们来看看我们的Point Tuples

1> Point = {point, 10, 45}.

{point, 10, 45}.

       假设我们想要从Point中取出XY并给他们赋值,我们可以这样做:

2> {point, X, Y} = Point.

{point,10,45}

3> X.

10

4> Y.

45

       在命令的第二行,X对应着10Y对应着45.表达式Lhs = Rhs是定义Rhs的,所以shell打印{point1045}

       正如你所见,等号两边的数据必须有相同的元素数据,并且等号一边的元素必须和与他类似的数值绑定。

       现在假设你这样输入:

5> {point, C, C} = Point.

=ERROR REPORT==== 28-Oct-2006::17:17:00 ===

Error in process <0.32.0> with exit value:

{{badmatch,{point,10,45}},[{erl_eval,expr,3}]}

       会发生什么?{pointCC}的格式和{point1045}并不匹配,因为C不同同时为1045。因此,格式匹配失败,系统打印出一个错误的消息。

       如果你有一个复杂的元祖,你可以从元祖中取出这些值,但是需要通过编写一个有相同格式的元祖,然后在此格式中赋给你想要的值。

       为了说明这些,我们首先定义一个包括复杂结构的变量person

1> Person={person,{name,{first,joe},{last,armstrong}},{footsize,42}}.

{person,{name,{first,joe},{last,armstrong}},{footsize,42}}

       现在我们来提取person的名字:

2> {_,{_,{_,Who},_},_} = Person.

{person,{name,{first,joe},{last,armstrong}},{footsize,42}}

 

最后,打印出who的值:

3> Who.

Joe

       注意:在之前的例子中,我们使用_作为变量的占位符。符号_叫做匿名变量。与以往的常规变量不同,_并不用与任何值绑定。

2.10 列表

       我们使用列表来存储变量的这些值:这些你想从内存中得到的东西,行星的名字,你的主要参数返回的结果等等。

       我们建立列表通过把列表的元素封入到方括号中,并且把他们用逗号分开。这儿使我们建立的购物的例子:

1> ThingsToBuy = [{apples,10},{pears,6},{milk,3}].

[{apples,10},{pears,6},{milk,3}]

       单个的元素能够是任意类型的,所以,例如,我们可以这样写:

2> [1+7,hello,2-2,{cost, apple, 30-20},3].

[8,hello,0,{cost,apple,10},3]

 

术语:

       我们调用列表开头的第一个元素。如果你想设想移除列表的开头元素,剩下的叫做列表的尾元素。

       例如,如果我们有一个这样的列表[1,2,3,4,5],列表的头元素是1,列表尾是[2,3,4,5]。注意列表的头能够是任意的东西,然后可以处理列表的尾。

 

定义列表:

       如果T是一个list,那么[H|T]也是一个列表,它的头元素是H尾元素是T。符号|分隔了头和尾。[]是一个空的列表。

       无论何时我们构造一个列表使用[…|T]构造,我们应当保证T是一个列表。如果他是,那么新的列表将会是“模板形成”。如果T不是一个列表,那么新列表可以说成是“不当列表”。大多数的库函数假定列表是模板形成,并且不能为不当列表工作。

       通过编写[E1E2,….En|T],我们能够添加超过一种的元素来开始T。例如:

3> ThingsToBuy1 = [{oranges,4},{newspaper,1}|ThingsToBuy].

[{oranges,4},{newspaper,1},{apples,10},{pears,6},{milk,3}]

 

从列表中引用元素

       正如此,我们能够从列表中引用元素使用格式匹配操作。如果我们有非空的L列表,那么表达式[X|Y] = L,(XY并没有绑定变量)将会引用列表的头到X,列表尾到Y

       所以,我们在商店中,我们我购物清单1——我们做的第一件事是解包并存贮到他的头和尾:

4> [Buy1|ThingsToBuy2] = ThingsToBuy1.

[{oranges,4},{newspaper,1},{apples,10},{pears,6},{milk,3}]

       绑定成功

       Buy1|->{oranges,4}

同时

       ThingsToBuy2 7 [{newspaper,1}, {apples,10}, {pears,6}, {milk,3}].

我们去买桔子,我们可以取出新的元素:

5> [Buy2,Buy3|ThingsToBuy3] = ThingsToBuy2.

{newspaper,1},{apples,10},{pears,6},{milk,3}]

       Buy2 7 {newspaper,1}, Buy3 7 {apples,10},取出成功,ThingsTo-

Buy3 7 [{pears,6},{milk,3}]

2.11 字符串

       严格的说,Erlang没有字符串。字符串实际上仅仅是整数的列表。字符串在成对出现的(“)中间,所以,例如我们能这样写:

1> Name = "Hello".

"Hello"

注意:在一些编程语言中,字符串能够使用单引号或者是双引号。在Erlang中,你必须使用双引号。

       Hello“是列表的速记他代表了单个的字符。

       shell打印列表的值作为一个字符串,但是只有列表中的所有整数代表可打印的字符:

2> [1,2,3].

[1,2,3]

3> [83,117,114,112,114,105,115,101].

"Surprise"

4> [1,83,117,114,112,114,105,115,101].

[1,83,117,114,112,114,105,115,101].

       在表达式2中,列表[1,2,3]将会保持原样的打印出来。这是因为123不是可打印字符。

       在表达式3中,所有的列表中的元素是可打印字符,所以打印出来也是字符串。

       表达式4和表达式3一样,除了列表从1开始,这不是一个可打印字符。正因为这些打印结果没有改变。

       我们不需要知道那个整形代表什么特殊的字符。我们使用“dollar syntax “来达到这个目的。所以,例如,$a是一个整形代表着字符a,等等。

5> I = $s.

115

6> [I-32,$u,$r,$p,$r,$i,$s,$e].

"Surprise"

在字符串中设置字符

       字符串中的字符代表着Latin-1(ISO-8859-I)字符代码。例如,字符串中包括Swedish的名字Håkan将被编为[7222910797110]

       注意:一旦你输入[7222910797110]作为shell的表达式,你可以得不到你想要的:

1> [72,229,107,97,110].

"H/345kan"

       “Håkan”发生了什么—它去了哪里?这实际上与Erlang没有什么关系,但是对于Erlang的语言环境和终端的字符代码设置有关。

       至于Erlang而言,在一些编码中,字符串仅是一个整形的列表。如果他们打印Latin-1编码,他们应当正确的运行(如果你的终端设置是正确的)。

2.12 重谈模式匹配

       为了是本节圆满的结束,我们再一次谈到模式匹配。

       下面的表格是一些模式匹配和条件的例子。表格的目录3,标记结果,表示的是匹配的条件,这样变量的绑定将会创建。浏览这些例子,确保你真的理解他们:

Pattern             Term                        Result

{X,abc}             {123,abc}                     Succeeds X |123

{X,Y,Z}             {222,def,"cat"}                 Succeeds X |222, Y |def,

                                                                                                             Z |"cat"

{X,Y}               {333,ghi,"cat"}                 Fails—the tuples have

                                                  different shapes

X                   true                          Succeeds X |true

{X,Y,X}             {{abc,12},42,{abc,12}}          Succeeds X |{abc,12}, Y |42

{X,Y,X}             {{abc,12},42,true}              FailsX cannot be both

                                                                                                           {abc,12} and true

[H|T]                [1,2,3,4,5]                     Succeeds H |1, T |[2,3,4,5]

[H|T]               "cat"                          Succeeds H |99, T |"at"

[A,B,C|T]            [a,b,c,d,e,f]                    Succeeds A |a, B |b,

                                                       C |c, T |[d,e,f]

如果以上你有什么不明白请把表达式打入shell中,看看结果如何。

例如:

1> {X, abc} = {123, abc}.

{123,abc}.

2> X.

123

3> f().

ok

4> {X,Y,Z} = {222,def,"cat"}.

{222,def,"cat"}.

5> X.

222

6> Y.

def

...

注意:f()命令告诉shell忘记所有绑定的信息。在这个命令之后,所有变量都没有设置,所以第四行的X对于12行的X没有作用。

       现在我们熟悉了基本数据类型,简单指定和模式匹配,所以我们可以更上一个台阶来看看如何定义函数和系数。我们来看下一章节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值