本文最后更新于:June 30, 2023 pm

概要:Erlang程序设计基础知识讲解

申明:此系列文章来源于【https://gitee.com/yujian1018/erlang.git】,经过本人搬运整理,并非原作,希望作者收到我的邮件以后联系本人。如有侵权会及时删除。


1. 变量、模式匹配


Shell命令行常见操作

  1. %:注释;
  2. 变量首字母大写,单一赋值;
  3. 模式匹配;
  4. 原子:hello, ‘an atom with’;
  5. 元组tuple:元组嵌套{person,{a,1},{b,2}};
  6. 提取元组字段值Point = {point, 10, 45} {point, X, Y} = Point;
  7. 列表list: 定义列表ThingsToBuy1 = [{oranges,4}, {newspaper,1}|{ThingsToBuy}]
  8. 提取元素[Buy1|ThingsToBuy2] = ThingsToBuy1.
  9. 字符串:”hello”,注意:Erlang吗,没有字符串的说法,只有List,请看相关文章
  10. q()退出shll
  11. f()释放shell中的变量

2. 函数


面向函数编程:函数可以作为参数,也可以作为返回值,可以使用列表解析、断言、case/if、二进制、比特位、进制、ASCII码

  1. 函数
    函数类似于其他语言的函数定义

  2. 匿名函数

    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.
  3. 函数作为函数参数

    映射: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.
  4. 返回函数的函数

    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.
  5. 循环

    for(Max,Max,F) -> [F(Max)];
    for(I,Max,F)   -> [F(I)|for(I+1,Max,F)]
  6. 列表解析

    [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"]
  7. 算术表达式

    1+2.
    1/1.
    10*4.
  8. 断言:

    max(X,Y) when X > Y -> X;
    max(X,Y) -> Y.
    断言函数:
    f(X,Y) when is_integer(X), X > Y, Y < 6 -> X;
  9. 记录:record
    结构化数据,类似于MAP的结构。

  10. case表达式:

filter(P, [P|T]) ->
    case P(H) of
        true -> [H|filter(P,T}];
 false ->filter(P,T)
     end;
filter(P, []) -> [].
  1. if表达式:
test_if(Num) ->
	if
		Num>=5 ->
			10;
		(Num>=0) and (Num<5) ->
			0;
		Num<0 ->
			pass
end.
  1. 内建函数BIF
    内置函数是指那些出于某种需求而内置到 Erlang 虚拟机中的函数。内置函数常常实现那些在 Erlang 中不容易实现或者在 Erlang 中实现效率不高的函数。某些内置函数也可以只用函数名就调用,因为这些函数是由于默认属于 erlang 模块。可理解为标准库。

  2. 二进制数据

    <<>>
    <<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 通常用来保证字节对齐.
  3. 动态调用

    apply(libs, sum, [1,2,3,4]).注意:尽量避免过多的apply
  4. 指令

    模块:-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. 编译运行


  1. 退出:halt().导致数据库要恢复 q().安全退出,等价于init:stop().
  2. 取得加载路径:code:get_path().
    取得主目录:init:get_argument(home).
  3. 外部运行:D:/erl>erl.exe -noshell -s hello start -s init stop
  4. 帮助:help().

4. 并发


  1. 创建进程

    Pid = spawn(Fun)
    spawn(Mod, FuncName, Args).
  2. erlang消息机制

    发送消息:Pid!Message
    群发消息:Pid1!Pid2!Pid3...!Pidn!Message
    接收消息:receive ... end.
    例如:Pid = spawn(fun area_server0:loop/0).
         Pid!{rectangle, 6, 10}.
  3. 进程相关

    自身ID:self().
    Pid!{self(), Message}.
    例如:Pid = spawn(fun area_server1:loop/0).
         area_server1:rpc(Pid, {rectangle, 6, 10}).
  4. 设置进程数

    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. 分布式


  1. 单节点测试
    启动服务器:kvs.start().
    存储: kvs:store({location, joe}, “Stockholm”).
    kvs:store(weather, raining).
    查找: kvs:lookup(weather).
    kvs:lookup({location, joe}).

  2. 双节点测试
    启动服务器节点:
    D:/erl>erl -sname gandalf
    Eshell V5.7 (abort with ^G)
    (gandalf@zhongbingliu)1> kvs:start().
    true
    (gandalf@zhongbingliu)2>

  3. 调用者节点:

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}
  1. 客户机和服务器位于同一局域网的不同机器上
  2. 客户机和服务器位于因特网的不同机器上:确保4396端口通信正常,epmd会使用这个端口

6. 文件


  1. 读取文件
    file:consult("data1.data").
  2. 读取
    {ok, S} = file:open("data1.data", read). 
     io:read(S, ''). 
     io:get_line(S, ''). 
     file:close(S).
  3. 查找代码库位置
    code:which(file).
    d:/erl5.7/lib/kernel-2.13/ebin/file.beam
  4. 读取二进制数据
    file:read_file("data1.data").
    {ok, S} = file:open("data1.data", [read,binary,raw]).
    file:pread(S, 22, 46).
  5. 查找文件
    lib_find:files
  6. 写入文件
    {ok, S} = file:open("data2.data", write).
     io:format(S, "~s~n", ["Hello readers"]). 
     file:close(S).
  7. 随机写入
    {ok, S} = file:open("data3.data", [raw,write,binary]).
    file:pwrite(S, 10, <<"new">>).
  8. 目录操作
    file:list_dir("/").
      file:make_dir("abc").
      file:del_dir("abc").
  9. 文件属性
    file:read_file_info("data1.data").
  10. 文件操作
    file:copy("data1,data", "/").
            file:delete("data1").

7. 套接字


  1. Socket连接www:socket:nano_get_url().
  2. 启动服务器:server:start_nano_server().
  3. 编写客户端:client:nano_client_eval(“list_to_tuple([2+3*4,10+20])”).
  • 主动型:非阻塞 服务器接收消息的速度必须快于客户端发送的速度,否则服务器会因为消息缓冲-区塞满被消息淹没
  • 被动型:阻塞
  • 混合型:半阻塞

8. 数据库


  1. ETS是内存存储,速度快
  2. DETS是磁盘存储,可备份
  3. 创建表:ets:new
  4. 插入:insert(table, X)
  5. 查找:lookup(table, Key)
  6. 释放:dets:close(tableid) etd:delete(tableid)
  7. Mnesia数据库:
    创建表:-record...
    选取所有数据:do(qlc())...
    选取部分列:
    按条件选取:
    关连查询:
    增加数据:mnesia:write()
    删除数据:mnesia:delete()
    事务管理:mnesia:transaction(F)
    取消事务:mnesia:abort()
    启动表查看器:tv:start().

9. OTP


  1. 支持事务:使用异常捕捉进行回滚
  2. 支持热代码替换
  3. 错误日志
  4. 警报管理
  5. 应用程序监视器:appmon:start().

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

1.2基础操作 Previous
Erlang基于TCP协议的服务器开发 Next