【翻译】LearnYouSomeErlangForGreatGood(三):真·起始

  Erlang是一门相对小巧精简的语言(就像c比C++精简一样)。它内置了几种基本的数据类型,本章将尽可能多地介绍它们。强烈建议阅读本章,它将是你以后写Erlang程序的基石。


数字(Numbers)

  在Erlang Shell中,表达式必须以句号结尾,并跟上空白(换行,空格等),否则将不会被执行。你可以用逗号分隔语句,但只有最后一句的结果会被显示(其他语句还是会执行的)。对于很多人来说这显然是不习惯的语法,但自Erlang从Prolog(一门逻辑式编程语言)中实现出来起就已经如此了。
  用前面章节所描述的方法打开Erlang Shell,输入这些玩意!

1> 2 + 15.
17
2> 49 * 100.
4900
3> 1892 - 1472.
420
4> 5 / 2.
2.5
5> 5 div 2.
2
6> 5 rem 2.
1

  你应该已经发现Erlang不关心你输入了浮点数还是整数:处理计算时两种类型都是支持的。浮点数和整数大概是唯二的Erlang的算术运算符可以显示地为你处理的数据类型。除此之外,如果你想要整除的话,可以使用div,想要模运算,使用rem(取余)。
  请注意我们可以在一个表达式里使用多个运算符,且算术运算符将遵循常规的优先级原则。

7> (50 * 100) - 4999.
1
8> -(50 * 100 - 4999).
-1
9> -50 * (100 - 4999).
244950

  如果你想表示非十进制数字,以Base#Value格式输入(允许基于2..36进制):

10> 2#101010.
42
11> 8#0677.
447
12> 16#AE.
174

  太棒啦!Erlang使用上面那种奇怪的语法,拥有了你桌角的计算器功能!真有趣!
  这里写图片描述


不变的变量

  能做数学运算很棒,但不能存储结果是走不远的。因此,我们要有变量。如果你读过了本书的导言,就会知道在函数式程序里变量是不可变的。变量的行为可以用下面的7个表达式展示(注意变量以大写字母开头):

1> One.
* 1: variable 'One' is unbound
2> One = 1.
1
3> Un = Uno = One = 1.
1
4> Two = One + One.
2
5> Two = 2.       
2
6> Two = Two + 1.
** exception error: no match of right hand side value 3
7> two = 2.
** exception error: no match of right hand side value 2

  首先这些语句告诉我们你可以为变量赋值且只能赋值一次,其次你可以假装给变量赋值,如果这个变量已经被赋成了这个值。而如果变量被赋成了其他值,再次赋值Erlang将报错。这个观察非常正确,但解释起来有点复杂且牵扯到=运算符。=运算符将比较两边的值并在不相等时报错。如果它们相等,则返回这个值。

8> 47 = 45 + 2.
47
9> 47 = 45 + 3.
** exception error: no match of right hand side value 48

  当这个运算符和变量结合时功能就变成:如果左侧的项是变量且未绑定(没有值赋予它),Erlang将自动将右边的值绑定给左边的变量。因此,这次比较将会成功,且变量将在内存中保存这个值。
  =运算符的行为是一种叫“模式匹配”的东西的基础,很多函数式编程语言都有模式匹配,虽然Erlang的处”事”之道通常是考虑更灵活和完备的选择。我们将在到达本章的tuple和list类型时领略到模式匹配的更多细节,并在后面的函数章节体会到更多。
  命令1-7告诉了我们另一件事情:变量名必须以大写开头。命令7因two以小写字母开头而失败。技术上,变量也能以下划线(’_‘)开头,但习惯上仅用于你不关心的变量,只是为了记录它存储了什么。
  你也可以用一个单独的下划线来表示变量:

10> _ = 14+3.
17
11> _.
* 1: variable '_' is unbound

  不同于其他变量,它永远不会存储任何值。表示现在完全用不到,但我们需要的时候你知道它在那里。

  备注:如果你在shell里测试的时候赋错了值,可以使用f(Variable)来“擦除”一个变量。如果你想要清除所有变量,使用f()
   这个方法只能在shell下工作,仅仅是为了帮助你测试。我们在写真正的程序时,不能以那样的方式销毁变量。在Erlang的工业项目中这功能的意义在于以下情形:不中断运行一个shell几年是完全有可能的…我打赌在这段时间内变量X将被使用超过一次。
  


原子(Atom)

  Erlang变量不能以小写字母开头的罪魁祸首就是:原子。原子是以它自己名字为值的常量。你看到的就是它的全部,一点多的也没有。原子cat表示”cat”仅此而已。你不能玩弄它,你不能改变它,你不能将它切成碎片。它就是cat,完了。
  以单个小写字母开头的单词来创建原子,我们有一百种姿势创建原子:

1> atom.
atom
2> atoms_rule.
atoms_rule
3> atoms_rule@erlang.
atoms_rule@erlang
4> 'Atoms can be cheated!'.
'Atoms can be cheated!'
5> atom = 'atom'.
atom

  如果要表示非小写字母开头或包含不是数字和字母的原子,需要使用单引号括起来。
  表达式5也显示出带单引号的原子和同样的不带单引号的原子是完全一样的。
  这里写图片描述
  我将原子对比成以名字为值的常量。你以前可能使用过常量:例如,我有一些值代表眼睛的颜色:BLUE->1,BROWN->2,GREEN->3,OTHER->4。你得去匹配这些名字。而原子会让你忘掉这些名字:我的眼睛颜色可以直接就是’blue’、’brown’、’green’或’other’。这些颜色可以被使用在任何地方的任何代码中:这些值永远不会冲突且不会出现未定义的常量!如果你实在要定义带有值的常量,我们将在第四章(模块)看到如何去做。
  所以原子和数据组合,能够很有效地表示或限定一个数据。很少能找到单独使用原子的时候。所以我们不多花时间陪它玩了,它将在和其他数据组合中展现出真正的实力。

别喝太多鸡汤

  原子非常好用同时也是发消息和表示常量的一把好手。但在过多使用原子有一个陷阱:原子被’atom table’引用,并占用内存(32位系统4字节/原子,64位系统8字节/原子)。’atom table’不会被垃圾回收,所以原子会一直积累直到系统因内存使用或声明了1048577个原子后翻车。
  这意味着不要因为任何原因动态生成原子。例如你的系统需要是可靠的,所以当用户输入导致有人崩溃时创建原子告诉用户,你将会有严重的麻烦。原子应该被视为开发者的工具,因为它诚实,就是它本身。 

备注:有些原子是保留字并只能用于语言设计者想要的地方:函数名、运算符、表达式等。它们是:
after and andalso band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse query receive rem try when xor


布尔值和比较运算符(Boolean Algebra & Comparison operators)

  这里写图片描述
  如果我们无法讲出大和小、真和假之间的区别,我们就有大问题了。和其他语言一样,Erlang也有比较事物的布尔操作。
  布尔值简单而又直接:

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

备注andor布尔运算符将始终计算两边的值。如果你想要短路运算(仅当需要的时候才计算右边的值),使用andalsoorelse

  判断相等和不等也很简单,不过和许多其他语言中见过的符号稍有不同:

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

  首先,如果你常用的语言使用==!=来判断相等和不等,Erlang使用=:==/=。最后三行表达式(9到11行)向你展示了一个陷阱:Erlang在算术运算时不区分浮点数还是整数,但在比较的时候区分。不必担心,在这种情况下==/=操作符将拯救你。你需要记住这点,明确你是否需要使用全等。
  其他比较操作符有<(小于),>(大于),>=(大于等于)=<(小于等于)。最后一个反了(在我看来)并且是我代码里很多语法错误的凶手。多看几眼(keep an eye on,留心)=<吧。

12> 1 < 2.
true
13> 1 < 1.
false
14> 1 >= 1.
true
15> 1 =< 1.
true

  使用5 + llama(译注:美洲骆驼,神似草泥马,可以体会一下作者的趣味)5 == true会发生什么呢?没有比试试更好的办法了,然后就差点被错误信息吓死!
  

12> 5 + llama.
** exception error: bad argument in an arithmetic expression
in operator  +/2
called as 5 + llama

  救命啊!Erlang不喜欢你乱用它的基础类型!模拟器返回了不错的错误信息。它告诉我们它不喜欢+两边的参数中的某一个!
  Erlang也不是会对所有类型不对都疯掉:

13> 5 =:= true.
false

  为何有些操作符使用不同类型会被拒绝,而有些不会呢?Erlang不允许你将任何东西相加,却允许你比较任何东西。这是因为Erlang的创造者们认为实用比理论重要,这样将对简化像可以排序所有类型的通用排序算法有很大作用。它将使你的生活更简单,而且大部分时间确实可以。
  关于布尔值和运算符,最后一点需要强调的是:

14> 0 == false.
false
15> 1 < false.
true

  如果你来自过程式语言或大部分面向对象语言,对此将会经常抓狂。14行应该是true而15行应该是false!是的,false代表0而true是0以外的其他东西。除了Erlang之外。因为我骗了你,是的,我骗了你,嘲笑我吧。
  Erlang并没有类似true和false的布尔值。元素true和false都是原子,但它们被很好的集成到了语言里,所以你不会有任何问题直到你不想它们表示true或false。

备注:所有元素的正确比较顺序如下:
  number < atom < reference < fun < port < pid < tuple < list < bit string
  你暂时还不知道上面的所有类型,但通过本书你都会了解的。先记住这就是为什么你可以比较任何东西的原因!用Erlang的作者之一Joe Armstrong话来说:”实际的顺序并不重要——但良好设计的总顺序非常重要。”

元组(Tuple)

  元组是组织数据的一种方式。当你知道有多少项时,他可以把所有项组装到一起。在Erlang中,元组的格式是{Element1, Element2, Element3}。举个例子,当你需要传达笛卡尔坐标系里一个坐标时,我们可以用一个两项的元组来表示。

1> X = 10, Y = 4.
4
2> Point = {X,Y}.
{10,4}

列表(Lists)

  列表是很多函数式语言干活的主要工具。它被用来解决各种各样的问题,是Erlang中当之无愧的使用最多数据结构。列表可以包含任何东西!数字、原子、元表、其他列表。它满足了你所有的愿望。列表基本的声明方式是:[Element1, Element2, Element3]并且你可以混入多种类型数据:  

1> [1, 2, 3, {numbers,[4,5,6]}, 5.34, atom].
[1,2,3,{numbers,[4,5,6]},5.34,atom]

  很简单,不是吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值