本文最后更新于:June 30, 2023 pm
概要:Erlang程序设计基础知识讲解
申明:此系列文章来源于【https://gitee.com/yujian1018/erlang.git】,经过本人搬运整理,并非原作,希望作者收到我的邮件以后联系本人。如有侵权会及时删除。
1. 变量、模式匹配
Shell命令行常见操作
- %:注释;
- 变量首字母大写,单一赋值;
- 模式匹配;
- 原子:hello, ‘an atom with’;
- 元组tuple:元组嵌套{person,{a,1},{b,2}};
- 提取元组字段值Point = {point, 10, 45} {point, X, Y} = Point;
- 列表list: 定义列表ThingsToBuy1 = [{oranges,4}, {newspaper,1}|{ThingsToBuy}]
- 提取元素[Buy1|ThingsToBuy2] = ThingsToBuy1.
- 字符串:”hello”,注意:Erlang吗,没有字符串的说法,只有List,请看相关文章
- q()退出shll
- f()释放shell中的变量
2. 函数
面向函数编程:函数可以作为参数,也可以作为返回值,可以使用列表解析、断言、case/if、二进制、比特位、进制、ASCII码
函数
函数类似于其他语言的函数定义匿名函数
Double = fun(X) -> 2*X end. Double(2). Hypot = fun(X, Y) -> math:sqrt(X*X+Y*Y) end. TempConvert = fun({c,C}) -> {f, 32+C*9/5}; ({f,F}) -> {c, (F-32)*5/9} end.
函数作为函数参数
映射:lists:map(Double, [1,2,3,4]). 返回[2,4,6,8]. 过滤:lists:filter(Even, [1,2,3,4]). Even = fun(X) -> (X rem 2) =:= 0 end.
返回函数的函数
Fruit = [apple,pear,orange]. MakeTest = fun(L) -> (fun(X) -> lists:member(X,L) end) end. IsFruit = MakeTest(Fruit). IsFruit = fun(X) -> lists:member(X,[apple,pear,orange]) end.
循环
for(Max,Max,F) -> [F(Max)]; for(I,Max,F) -> [F(I)|for(I+1,Max,F)]
列表解析
[2*X || X <- L]. 定义:Buy = [{oranges,4},{newspaper,1},{apples,10},{pears,6},{milk,3}]. 乘积:[shop:cost(A)*B || {A,B} <- Buy] 求和:libs:sum([shop:cost(A)*B || {A,B} <- Buy]). (1)快速排序:L=[12,6,2,13,2,8,9,10]. qsort(L). (2)毕达哥拉斯三元组:libs:pythag(16). (3)变位词:libs:perms("123"). ["123","132","213","231","312","321"]
算术表达式
1+2. 1/1. 10*4.
断言:
max(X,Y) when X > Y -> X; max(X,Y) -> Y. 断言函数: f(X,Y) when is_integer(X), X > Y, Y < 6 -> X;
记录:record
结构化数据,类似于MAP的结构。case表达式:
filter(P, [P|T]) ->
case P(H) of
true -> [H|filter(P,T}];
false ->filter(P,T)
end;
filter(P, []) -> [].
- if表达式:
test_if(Num) ->
if
Num>=5 ->
10;
(Num>=0) and (Num<5) ->
0;
Num<0 ->
pass
end.
内建函数BIF
内置函数是指那些出于某种需求而内置到 Erlang 虚拟机中的函数。内置函数常常实现那些在 Erlang 中不容易实现或者在 Erlang 中实现效率不高的函数。某些内置函数也可以只用函数名就调用,因为这些函数是由于默认属于 erlang 模块。可理解为标准库。二进制数据
<<>> <<E1,...,En>> Ei = Value | Value:Size | Value/TypeSpecifierList | Value:Size/TypeSpecifierList Type= integer | float | binary | bytes | bitstring | bits | utf8 | utf16 | utf32 Signedness= signed | unsigned (整型值时有意义,默认是unsigned) Endianness= big | little | native 默认是big Unit= unit:IntegerLiteral unit是每个数据段的size,允许的取值范围是1..256 size和unit的乘积是数据占用的二进制位数,且必须可以被8整除 unit 通常用来保证字节对齐.
动态调用
apply(libs, sum, [1,2,3,4]).注意:尽量避免过多的apply。
指令
模块:-module(modname). 引入:-import(modname, [fun/1]). 可以不写模块名直接引用函数名 导出:-export([name1/1, name2/2]). 编译属性:-compile(options). 模块版本:-vsn(Version). 用户定义属性:-SomeTag(Value). 输出属性:attr:module_info(). attr:module_info(attributes). 引用函数:fun Mod:RemoteFunc/Arity 包含文件:-include(Filename). -include_lib(Name). 列表操作符:[1,2,3]++[4,5,6] [1,2,3]--[2,3] 进制:K#123 $语法:$C 表示ASCII 字典:erase(), put(x, 20),get(x), erase(x) 短路表达式:Epr1 orelse Epr2. Epr1 andalse Epr2.
3. 编译运行
- 退出:halt().导致数据库要恢复 q().安全退出,等价于init:stop().
- 取得加载路径:code:get_path().
取得主目录:init:get_argument(home). - 外部运行:D:/erl>erl.exe -noshell -s hello start -s init stop
- 帮助:help().
4. 并发
创建进程
Pid = spawn(Fun) spawn(Mod, FuncName, Args).
erlang消息机制
发送消息:Pid!Message 群发消息:Pid1!Pid2!Pid3...!Pidn!Message 接收消息:receive ... end. 例如:Pid = spawn(fun area_server0:loop/0). Pid!{rectangle, 6, 10}.
进程相关
自身ID:self(). Pid!{self(), Message}. 例如:Pid = spawn(fun area_server1:loop/0). area_server1:rpc(Pid, {rectangle, 6, 10}).
设置进程数
D:/erl>erl +P 500000 测试启动时间:process:max(400000). register(AnAtom, Pid). 注册进程别名 unregister(AnAtom). 溢出注册进程 whereis(AnAtom) -> Pid | undefined 判断是否注册 registered() -> [AnAtom::atom()] 取得所有注册进程 注册时钟:clock:start(5000, fun() -> io:format("TICK ~p~n", [erlang:now()]) end). 停止时钟:clock:stop().
5. 分布式
单节点测试
启动服务器:kvs.start().
存储: kvs:store({location, joe}, “Stockholm”).
kvs:store(weather, raining).
查找: kvs:lookup(weather).
kvs:lookup({location, joe}).双节点测试
启动服务器节点:
D:/erl>erl -sname gandalf
Eshell V5.7 (abort with ^G)
(gandalf@zhongbingliu)1> kvs:start().
true
(gandalf@zhongbingliu)2>调用者节点:
D:/erl>erl -sname bilbo
Eshell V5.7 (abort with ^G)
(bilbo@zhongbingliu)1> rpc:call(gandalf@zhongbingliu, kvs, store, [weather, fine]).
true
(bilbo@zhongbingliu)2> rpc:call(gandalf@zhongbingliu, kvs, lookup, [weather]).
{ok,fine}
- 客户机和服务器位于同一局域网的不同机器上
- 客户机和服务器位于因特网的不同机器上:确保4396端口通信正常,epmd会使用这个端口
6. 文件
- 读取文件
file:consult("data1.data").
- 读取
{ok, S} = file:open("data1.data", read). io:read(S, ''). io:get_line(S, ''). file:close(S).
- 查找代码库位置
code:which(file). d:/erl5.7/lib/kernel-2.13/ebin/file.beam
- 读取二进制数据
file:read_file("data1.data"). {ok, S} = file:open("data1.data", [read,binary,raw]). file:pread(S, 22, 46).
- 查找文件
lib_find:files
- 写入文件
{ok, S} = file:open("data2.data", write). io:format(S, "~s~n", ["Hello readers"]). file:close(S).
- 随机写入
{ok, S} = file:open("data3.data", [raw,write,binary]). file:pwrite(S, 10, <<"new">>).
- 目录操作
file:list_dir("/"). file:make_dir("abc"). file:del_dir("abc").
- 文件属性
file:read_file_info("data1.data").
- 文件操作
file:copy("data1,data", "/"). file:delete("data1").
7. 套接字
- Socket连接www:socket:nano_get_url().
- 启动服务器:server:start_nano_server().
- 编写客户端:client:nano_client_eval(“list_to_tuple([2+3*4,10+20])”).
- 主动型:非阻塞 服务器接收消息的速度必须快于客户端发送的速度,否则服务器会因为消息缓冲-区塞满被消息淹没
- 被动型:阻塞
- 混合型:半阻塞
8. 数据库
- ETS是内存存储,速度快
- DETS是磁盘存储,可备份
- 创建表:ets:new
- 插入:insert(table, X)
- 查找:lookup(table, Key)
- 释放:dets:close(tableid) etd:delete(tableid)
- Mnesia数据库:
创建表:-record... 选取所有数据:do(qlc())... 选取部分列: 按条件选取: 关连查询: 增加数据:mnesia:write() 删除数据:mnesia:delete() 事务管理:mnesia:transaction(F) 取消事务:mnesia:abort() 启动表查看器:tv:start().
9. OTP
- 支持事务:使用异常捕捉进行回滚
- 支持热代码替换
- 错误日志
- 警报管理
- 应用程序监视器:appmon:start().
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!