Erlang学习世界
学习Erlang的理由
- 希望编写能在多核计算机上运行更快的程序
- 希望编写不停机即可修改的可容错性程序
- 希望尝试传说中的“函数式语言”的魅力
- 希望使用一种语言,它既在大规模工业产品中经过实践检验,又不乏优秀的类库与活跃的社区
- 不希望在冗长烦琐的代码中耗费时间
- Erlang没有可变状态,也就没有共享内存,更没有锁,这一切都有利于并行化程序的编写和执行
Erlang程序可以由几百万个超轻量级的进程组成。这些进程可以运行在单处理器,多核处理器或处理器网络中。
Erlang的语法记要
百分号(%)表示注释的开始 . 表示表达式的完成 Erlang采用不定长的整数来进行整数的算术演算。因此,不用担心运算溢出。 f()可以释放所有绑定的变量。执行这个命令后,所有的变量都变成了自由变量。 在Erlang中,同一个模块的两个函数,如果同名但不同目(参数),则这两个函数被认为是不相同的。 @spec 是Erlang类型文档标记。常用这个标记在文档中描述函数的参数及其返回类型。 module 和 function名字都必须是小写 变量必须以大写字母开头 Erlang 中只有public和private的函数,public的函数是指export出去的,其他的是private的 一个函数的声明是名字加上参数个数,例如start/1,stop/0 在模式匹配时,下划线(_) 表示匿名变量,可以匹配任何值 用$ 加字符可以取得相对应的ascii码,如$a = 97.
变量
- 变量必须以大写字母开头,
- 变量是单一赋值变量,只能一次性的给定。含有一个被赋予的值,则被称为绑定变量,否则,则为自由变量。
- =是一个模式匹配运算符。当X是一个自由变量时,它的行为与赋值一致,换之,则为模式匹配。
原子
- 原子用来表示不同的非数字常量值,类似于全局变量,无需使用宏定义或者包含文件即可使用。
- 原子必须以小写字母开头,后跟数字字母或下划线,邮件符。使用单引号引起来的字符也是原子。原子的值就是原子自身
元组
- 将若干个逗号(,)分割的值用花括号{}引起来,就形成了一个元组(tuple)。用来表示由多个项形成单一的实体,类似于C中的结构体。
- 创建元组
Name = {name,joe}. Age = {age,20}. Person = {person,Name,Age}. => {person,{name,joe},{age,20}}
- 提取元组中的字段值 <code erlang> {person,{_,Who},Age} = Person.
Who. ⇒ jo </code> 为占位符,表示那些我们不关心的变量。与常规常量不同,在同一模式中的不同地方,各个所绑定的值不必相同
列表
- 将若干个以逗号(,)分割的值用一对方括号[]括起来,就形成了一个列表,用于存储数目可变的东西。
List = [Name,Age]. => [{name,joe},{age,20}]
注意,列表的头可以是任何东西,但是列表的尾通常还是一个列表
- 从列表中提取元素
[N|Last] = List. N. => {name,joe}
字符串
- 严格地讲,erlang中没有字符串,字符串实际上是一个整数列表。用双引号“”将一串字符括起来就是一个字符串,在erlang中,必须使用双引号。
- shell打印一串列表值时,如果列表中的所有整数全部都是可打印字符,则把列表当字符串来打印。
[83,117,114,112,114,105,115,101]. => "Surprise" [1,83,117,114,112,114,105,115,101]. => [1,83,117,114,112,114,105,115,101]. <- 其中包括一个“1”不是可打印字符
标点符号
在Erlang中会使用三种标点符号
逗号(,)
用来分隔函数调用,数据构造器以及模式中的参数
分号(;)
用来分隔子句: 分段的函数定义,case语句,if语句,try...cacth语句以及receive表达式
句号(.)
用来在shell中分隔完整的函数和表达式
匿名函数
fun就匿名函数,以end结束
28> Temp = fun({c,C})->{f,32+C*9/5}; 28> ({f,F})->{c,(F-32)*5/9} end. #Fun<erl_eval.6.13229925> 29> Temp({c,100}). {f,212.0} 30> Temp({f,212}). {c,100.0}
列表处理
-module(shop2). -export([total/1]). -import(lists,[map/2,sum/1]). -import(shop,[cost/1]). total(L)-> sum(L).
列表解析
记号[ F(X) || X ← L ]代表“由F(X)组成的列表,其中X值来自于列表L”
例一: 求列表中各自数字的平方
List = [1,2,3,4]. [ X*X || X <- List]. => [1,4,9,16].
例二: 计算水果的各自总价
Fruits=[{orange,4},{apples,5},{milk,4}]. [shop:cost(What)*N || {What,N} <- Fruits ]. => [20,10,28]
例三: 把元组的数量乘2
Fruits = [{orange,4},{apples,5},{milk,4}]. [{What,N*2} || {What,N} <- Fruits ]. => [{orange,8},{apples,10},{milk,8}]
列表快速排序
-module(lib_misc). -export([qsort/1]). qsort([])->[]; qsort([Pivot|T])-> qsort([X || X<-T,X<Pivot]) ++ [Pivot] ++ qsort([X || X<-T,X>=Pivot]).
列表分离元素
X–Y是列表的分离操作符,它从列表X中分离出元素Y
List=[1,2,3,4]. List -- [2,3]. => [1,4]
记录
记录是一种把一个名称和元组中的一个元素对应起来的方法。语法:
-record( Name, { key1 = value1, key2 = value2, key3, } ).
Name,key1,key2..等是记录中的字段名,这些名字必须是原子(全部小写)。记录中的每个字段都可以有默认值。如果在记录创建的时候,如果没有指定值,则使用默认值。
定义记录文档 : records.hrl
-record(todo,{status=reminder,who=joe,text}).
读取记录
1> rr("records.hrl").
创建和更新记录
X=#todo{}. X1=#todo{status=urgent,text="Fix error in book"}. X2=X1#todo{status=done}.
获取记录字段
#todo{who=W,text=Text} = X2. or X2#todo.text.
BIF内建函数
BIF (Build-in function),顾名思义就是Erlang中的内置函数。它们通常用来实现完成那些无法用Erlang完成的任务。如,将列表转换成元组或者获取当前的时间和日期。
1> tuple_to_list({12,cat,"Hello"}). [12,cat,"Hello"] 2> time(). {20,0,3}
所有的BIF都在Erlang模块之中,而且大部分常用的BIF都已经被自动导入,因此,我们调用的时候只要写直接的函数名即可。
二进制数据
在Erlang中可以使用一种二进制(binary)数据的结构来存储大量的原始数据。相对于元组和列表,二进制类型更加节省内存,而且运行时系统也对此进行了优化,对二进制数据的输入输出会更加高效。
如:
1> <<5,10,20>>. <<5,10,20>> 2> <<"hello">>. <<"hello">> 3> <<99,97,116>>. <<"cat">>
在二进制数据中使用的整数,每一个都必须要在0和255之间,如果超出255,将显示为0。
由字符序组成的二进制数据等同于由其每一个字符的ASCII编码组成的二进制数据,即«99,97,116» 等同于 «“cat”»