Erlang开发环境搭建:
1.下载安装erlang,最新版5.9.1,配置环境变量
查看安装成功否:erl -version
2.eclipse插件Erlide
3.配置Erlide,Eclipse里设置Erlang安装路径
基础特性:
Erlang的实现基于虚拟机beam;
COP面向并发编程;
并发(建立在非共享内存基础上,线程是共享内存的,进程不是);
Erlang具备一个使用消息传递的基于进程(轻量级进程)的并发模型;
Erlang的并发机制是轻量级的,如进程只占用极少的内存,进程的创建、删除以及消息传递也都只涉及极少量的计算;
分布式;
Erlang没有内存共享。所有进程间交互都通过异步消息传递完成;
Erlang可以简单地调用其他语言编写的程序。通过Erlang的接口系统,这些程序对于程序员来看就好像是用Erlang编写的一样。
模式识别
模式识别用于将模式与项式进行匹配。如果一个模式与项式具备相同的结构则匹配成功,并且模式中的所
有变量将被绑定到项式中相应位置上出现的数据结构。
> N = {12, banana}.
{12,banana}
> {A, B} = N.
{12,banana}
> A.
12
> B.
banana
{_,L,_} = {fred,{likes, [wine, women, song]},{drinks, [whisky, beer]}}.
下划线(写作“_”)代表特殊的匿名变量或无所谓变量。在语法要求需要一个变量但又不关心变量的取值
时,它可用作占位符。
并发(scala的actor就是参考erlang)
Erlang是一门并发编程语言——这意味着在Erlang中可直接对并行活动(进程)进行编程,并且其并行机
制是由Erlang而不是宿主操作系统提供的。
为了对一组并行活动进行控制,Erlang提供了多进程原语:spawn用于启动一个并行计算(称为进
程);send向一个进程发送一条消息;而receive从一个进程中接收一条消息。
spawn/3启动一个并发进程并返回一个可用于向该进程发送消息或从该进程接收消息的标识符。
Pid ! Msg语法用于消息发送。Pid是代表一个进程的身份的表达式或常量。
我们可以简单认为send发生一条消息而receive接收一条消息,然而更准确的描述则是send将一条消息发送
至一个进程的邮箱,而receive尝试从当前进程的邮箱中取出一条消息。
receive是有选择性的,也就是说,它从等候接收进程关注的消息队列中取走第一条与消息模式相匹配的消
息。如果找不到与接收模式相匹配的消息,则进程继续挂起直至下一条消息到来——未匹配的消息被保存
用于后续处理。
语法:
函数式语言
动态语言,没有类型声明
erlang属于脚本语言,相对于编译型语言性能较低,但是erlang代码可以编译,运行时环境是一个虚拟机,代码经编译后可随处运行,并且极大的提高了执行效率。
尾递归
编辑器可以采用Emacs
%表示注释的开始
%%在emacs erlang-mode中会被识别,从而启动注释行的自动缩排功能。
.表示一个句柄的结束
Erlang中不用担心整数运算溢出
所有的变量都必须以大写字母开头
变量不变
Erlang的变量是单一赋值变量,单一赋值变量的值只能一次性地给定。
一个变量一旦被赋了值,你想再次改变它,就会得到一个错误(一个匹配失败的错误)。
一个变量如果含有一个被赋予的值,就称为绑定变量,否则,称为自由变量。
所有的变量一开始都是自由的。
模式匹配
(=)在Erlang中表示一个模式匹配操作,匹配符号两边的结构要一样。
5 div 3. 整数除
5 rem 3. 取余数
{point,C,C}与{point,10,45}不能匹配,因为C不可能同时等于10和45,因此模式匹配失败。
{test,X,Y}={test2,10,20}.不能匹配,因为原子test与test2不同.
{test2,X,Y}={test2,10,20}.匹配成功,原子的作用凸显啊。
原子
原子是一串以小写字母开头,后跟数字字母或下划线或邮件符号@的字符。
使用单引号引起来的字符也是原子。使用这种形式,我们就能使得原子可以用大写字母作为开头或者包含非数字字符。
如:'Monday'、'+'、'*'、'an atom with spaces'。
也可以将不需要使用引号的原子引起来,'a'实际上就等同于a
一个原子的值就是原子自身。
元组(区别与其它语言的特殊存在)
声明一个元组:P={joe,1.82}.
Erlang使用垃圾搜集器去收回没有使用的内存,因此我们不用担心内存分配的问题。
若在创建数据结构时试图引用一个未定义的变量,系统会给出一个错误。
列表
声明一个列表:ThingsToBuy=[{apples,10},{pears,6},{milk,3}].
列表中各个元素可以有各自不同的类型,如:
[1+7,hello,2-2,{cost,apple,30-20},3]
列表的第一个元素称为列表的头(head),移除头,剩下的就是列表的尾(tail)。
列表的头可以是任何东西,但是列表的尾通常还是一个列表。
访问列表的头是一个非常高效的操作,因此实际上所有的列表处理函数都是从提取列表头开始的,先对头处理,然后继续处理列表的尾。
[H|T]这个列表以H为头,以T为尾,竖线符号(|)可以将列表的头尾分开,而[]则是空列表。
当我们用[...|T]来构造一个列表时,都应该保证T是一个列表。
字符串
严格地讲,Erlang中并没有字符串,字符串实际上就是一个整数列表。每个char都是对应一个数字(ASCII码表),可以使用$符号来表示字符的整数值。如:
1>I=$s.
115
Erlang中字符串只能用双引号,不能用单引号。
字符串中的字符是Latin-1(ISO-8859-1)编码的字符。
[H|T]="cat". 结果:H=99,T="at"
f()会让shell释放它所绑定过的所有变量,执行这个命令后,所有的变量都变成自由变量。
模块
模块文件通常存放在以.erl为扩展名的文件中,要运行一个模块,首先需要编译它,编译成功后的模块文件其扩展名是.beam。
创建一个函数
area({rectangle,Width,Ht}) -> Width*Ht;
area({circle,R}) -> 3.14159*R*R.
调用方法
geometry:area({circle,1.4}). geometry模块名,area方法名 。
函数
同名不同目的函数
函数的目(arity)就是它所拥有的参数数量。在Erlang中,同一个模块中的两个函数,如果他们同名但是目并不相同,这样的2个函数被认为是完全不同的,它们之间除了名字恰巧相同之外,彼此之间再无其他关联。
定义一个模块
-module(hw).
-export([area/1]).//area方法名,1参数个数,只有从一个模块中导出的函数才能在模块之外调用
-import(lists,[map/2,sum/1]).
area({rectangle,Width,Htry}) -> Width*Htry;
area({circle,R}) -> 3.14159*R*R.
匿名函数fun
Z=fun(X) -> 2*X end.
Z(2).
fun也可以拥有若干个不同字句
TempConvert=fun({c,C}) -> {f,32+C*9/5};
fun({f,F}) -> {c,(F-32)*5/9}
end.
高阶函数,这些能够返回fun或接受fun作为参数的函数被称为高阶函数.
lists:map(F,L). 将fun F应用到列表L的每一个元素上,并返回一个新列表。
lists:filter(P,L). 将列表L中的每一个能满足P(E)为true的元素组成。
lists:seq(1,N). 返回一个由1到N整数组成的列表。
Even=fun(X) -> (X rem 2) =:= 0 end.
=:=是一个恒等测试符号。
lists.map(Even,[1,2,3,4,5,6,8]).
[false,true,false,true,false,true,true]
lists.filter(Even,[1,2,3,4,5,6,8]).
[2,4,6,8]
定义自己的抽象流程控制
Erlang没有for、while这些语句,都被模式匹配和高阶函数替代了,如果需要额外控制结构,可以自己定义一个。
创建自己的控制结构、编写返回fun的函数,这些实际中都是很少用到,上百个模块可能才有一两个用到。返回fun的函数通常都不容易调试,但另一方面这一基数可以用来解决诸如延迟求值、可重入的解析器、解析组合子等问题,因为这些问题本身就是返回解析器的函数。
列表解析
L=[1,2,3,4,5].
[2*X || X <- L].
输出:[2,4,6,8,10]
[F(X) || X <- L]代表由F(X)组成的列表,其中X是取值于列表L。
列表中的生成器部分也可以像过滤器一样工作,如:
[X || {a,X} <- [{a,1},{b,2},{c,3},{a,4},hello,"wow"]].
毕达哥拉三元组
变位词
断言
断言序列:(;)分开的断言集合中只要一个断言为true,那么整个断言序列就为true。
(,)分开的断言集合中只有所有的断言都为true,整个断言序列才为true。
断言谓词
断言BIF
记录,记录只是元组的伪装,记录就是元组,只是使元组带了个key
创建一个记录:
-record(todo,{status=reminder,who=joe,text}). //key、value
创建记录的实例:
X=#todo{}. //省略了key所以采用记录定义中的默认值
X1=#todo{sttus=urgent,text="Fix errata in book"}.
X2=X1#todo{status=done}. //改变了status的值
取值
#todo{who=W,text=Text}=X2.
W 输出 joe
取某一个值:X2#todo.text.
输出"Fix errate in book"
记录#todo{status=done,who=joe,text="Fix errata in book"}.
元组{todo,done,joe,"Fix errata in book"}.
case of end
if end
List ++ [H] 这个一个极为抵消的操作,切勿这样书写。
异常
exit(Why),当想要终止当进程时需要用到这个函数。如果这个异常未被捕获,那么系统会向所有与当前进程相关连的进程广播{'EXIT',Pid,Why}消息。
throw(Why)
erlang:error(Why)
try ... of
....
catch
....
after //相当于java中的finally,可以省略
....
end
erlang:get_stacktrace() 栈跟踪信息
进阶
BIF是built-in function(内建函数)的缩写。
Erlang类型文档标记:@spec func(Arg1,...,Argn) -> Val
比特语法
binary_to_term term_to_binary
封包:M=<<X:3,Y:7,Z:6>> //16个bit字长的内存区域中,X占3个字节,Y占7个,Z占6个。
解包:<<X:3,Y:7,Z:6>>=M
<<E1,E2,...,En>>,每个Ei代表了二进制数据中的一个单独区块,有4种形式:
Ei=Value |
Value:Size |
Value/TypeSpecifierList |
Value:Size/TypeSpecifierList
TypeSpecifierList列表的项有以下值:@type End=big | little | native
apply(Mod,Func,[Arg1,Arg2,...,ArgN])将Mod模块中的Func函数应用到参数Arg1,Arg2...ArgN上,它和下面的这种调用方式是等价的:Mod:Func(Arg1,Arg2,...,ArgN)
apply的功能是让你向一个模块中的某个函数传递参数并调用此函数,它与直接函数调用的区别在于,模块名和函数名可以动态计算。
如果可能要尽量避免使用apply,如果某个函数的参数个数是已知的,那么形如M:F(Arg1,Arg2,...,ArgN)的函数调用要优于apply。当通过apply进行调用时,很多分析工具将无法分析出其中的工作细节,而且编译器也肯定不能对其进行优化,因此要尽量少用apply.
预定义模块属性:
-modelue(modname) //模块定义
-import(list2,[map/2]) //导入模块
-export([a/2,b/1]) //导出模块,导出的方法可以被外部模块调用
-compile(Options) //编译器选项
-compile(export_all) //它告诉编译器把模块中的每个函数都导出
-vsn(Version) //模块版本
-include(Filename) //包含以.hrl为扩展名的文件
用户定义模块属性:
-SomeTag(Value). // Sometag必须是一个原子,Value必须是一个文字项。
Erlang源代码文件默认以ISO-8859-1(Latin-1)字符集进行编码,这意味着Latin-1的可打印字符可以无需转义符而独立使用。
Erlang内部没有字符数据类型,字符串不是一个真正的类型,而是用一串整数列表来表示。
Unicode字符串也可以使用一串整数列表来表示,不过从Erlang证书列表中解析和生成的Unicode字符仍然存在一定的限制。
在一个格式化串中,~w的意思是对一个列表不做任何修饰的打印原始结果。
++和--是对列表进行进行添加和删除的中缀操作符。
A++B意味着把A和B加起来(实际上是B附加到A).
A--B从列表A中删除列表B。注意:如果符号X在B中出现K次,那么在A中只会按顺序删除K个X。
宏的语法;
-define(Constant,Replacement).
-define(Func(Var1,Var2,...,Var),Replacement).
K进制整数:不以10为进制的整数可以用语法K#Digits来表示。如二进制2#00101010
$语法:语法$C表示ASCII字符C的整数值,因此$a是97的简写。
进程字典
Erlang的每一个进程都由自己的私有数据存储,叫做进程字典。是有一系列键值对组成的关联数组。
@spec put(Key,Value) -> OldValue. //返回Key的前一个关联值,没有前关联值返回原子undefined。
@spec get(Key) -> Value.
@spec get() -> [{Key,Value}].
@spec get_keys(Value) -> [Key]. //返回字典中值为Value的健的列表。
@spec erase(Key) -> Value. //如果存在Key对应的值就返回对应的值,否则返回原子undefine,最后删除与键Key相关的值。
@spec erase() -> [{Key,Value}].删除整个进程字典,返回值由{Key,Value}元组组成的列表。
如果使用进程字典,那么代码不再是没有副作用的,因此尽量避免使用进程字典。
引用是全局唯一的Erlang值,创建引用erlang:make_ref().
短路布尔表达式
比较表达式
X/=Y //X不等于Y
X=/=Y //X不全等于Y
X==Y //X等于Y
X=:=Y //X全等于Y
Erlang按照下面的方式为所有类型都定义了大小比较的顺序:
number<atom<reference<fun<port<pid<tuple<list<binary
==仅使用于浮点数和整数的比较,=:=则用于比较两个项目是否全等。99%情况下都应该使用=:=
下划线变量主要用途:
1.命名一个不准备使用的变量,比如open(File,_Mode)会比open(File,_)更具可读性。
2.为了方便进行程序调试。
escript运行,无需编译直接运行。
崩溃转储,如果Erlang崩溃了,会留下一个erl_crash.dump的文件,分析此文件需要一个基于web的崩溃分析器,启动分析器的命令是:webtool:start().