《Erlang程序设计》学习笔记-第5章 顺序型编程进阶

第5章 顺序型编程进阶

1. 所有的BIF都在erlang模块中,大部分常用的BIF都已被自动导入(也就是说还有一些不常用的没有自动导入)。

2. 二进制数据相对于元组和列表,它更加节省内存,输入输出更加高效。
3. 在书写和打印时,二进制数据用一组以<<和>>括起来的整数或字符序列的形式出现。
    如:<<5,10,20>>. <<"hello">>
    整数要在0-255之间,字符相当于其对应的ASCII码。
4. 可以通过BIF或二进制语法来构造或提取二进制数据。
5. 操纵二进制数据的BIF
    @spec list_to_binary(IoList) -> binary()
        其中IoList是一个列表,其中的元素可以是0~255的整数、二进制数据或者另外一个IoList。亦即IoList可以是一个嵌套的列表。
    @spec split_binary(Bin, Pos) -> {Bin1, Bin2}
        从Pos位置将Bin分成两部分。如果是从1开始的话,第Pos个元素被分在了Bin1中。
    @spec term_to_binary(Term) -> Bin
        可以将任何一个Erlang值转化为二进制数据。转化成的数据可以保存在文件中,通过网络发送等。(如何发送的C写的程序的话,C程序如何解析呢?)
    @spec binary_to_term(Bin) -> Term
        term_to_binary的逆函数。
    @spec size(Bin) -> Int
        返回二进制数据的长度。

6. 比特语法
    <<E1, E2, ..., En>>
    Ei = Value |            %% Size省略时整数是8位,浮点型是64位
        Value:Size |        %% Size代表单元区块的长度,有可能有多个区块(Unit),整个区块的长度Size*Unit
        Value/TypeSpecifierList |
        Value:Size/TypeSpecifierList
    TypeSpecifierList是一个由连字符(-)间隔的形如End-Sign-Type-Unit的列表。 

    其中@type End = big | little | native    默认值是big
    @type Sign = signed | unsigned        默认值是unsigned
    @type Type = integer | float | binary    默认值是integer
    @Unit = 1|2|...|255        当Type是integer或float时,Unit的默认值是1; 当Type是binary,Unit的默认值是8
7. 测试本机的整数表示法:
    {<<16#12345678:32/big>>, <<16#12345678:32/little>>, <<16#12345678:32/native>>, <<16#12345678:32>>}
8. 如果I是一个整数,<<I:32>>可以将I转换一个32位长的二进制数据。

9. apply(Mod, Func, [Arg1, Arg2, ..., ArgN])调用Mod模块中的Func函数,Arg1~ArgN是Func的参数。apply的好处是可以动态改变模块和函数。
10. 预定义属性:(-record()和-include()不是属性)
    -module(modname).    %% 模块名要与文件名一致,这个属性必须是文件的第一个属性
    -import(Mod, [Name1/Arity1, Name2/Arity2, ...]).     %% 从Mod模块中导入函数
    -export([Name1/Arity1, Name2/Arity2, ...]).    %% 从当前模块中导出函数。
    -compile(Options).    %% 向编译器选项列表中添加Options。Options是一个编译器选项或者一个编译器选项列表(在compile模块手册中)
                            调试程序时可以用-compile(export_all).导出当前模块的所有函数。
    -vsn(Version).    %%Version可以是任何形式的文字项。
11. 用户定义属性语法:-SomeTag(Value). SomeTag必须是原子,Value必须是文字项。
12. Mod:module_info()返回一个与编译模块相关的所有元数据的属性列表。
    Mod:module_info(attributes)则返回与文件相关的特定属性的列表。
    还有Mod:module_info(exports), Mod:module_info(imports), Mod:module_info(compile)。
13. Mod:module_info/0, Mod:module_info/1是编译器在编译源文件时自动加入到模块中的函数。(我想可能在模块加载时有用。)
14. 可以用beam_lib:chunks("test.beam", [attributes])来看一下模块的属性信息。这个函数可以在没有加载模块时对模块进行分析并提取属性。
15. 块表达式:以逗号分隔一个串表达式,其值是最后一个表达式的值。在语法中需要一个表达式,而我们却要多个表达式的时候,可以用一下。
    begin
        Expr1,
        ...,
        ExprN
    end
16. 布尔类型:erlang中没有独立的布尔类型,通常用原子true和false来代替吧。
17. 布尔表达式:
    逻辑非:    not B1
    逻辑与:    B1 and B2
    逻辑或:    B1 or B2
    逻辑异或:    B1 xor B2

18.编译预处理:命令compile:file(M, ['p'])可以对M.erl文件进行预处理,处理完后输出M.P文件,这个文件中存入所有经过扩展的宏和所有已经手插入的包含文件。

19. 转义符:在字符串(也就是列表)或使用单引号的原子中,可以使用转义字符。

20. 在 erlang中,任何可以被求出值的东西都被称作表达式。这就意味着catch, if, try...catch等都是表达式。而类似记录和模块属性等,这些不能被求值的都不是表达式。表达式序列是一系统以逗号分隔的表达式,这些表达式应该紧 接放置在->之后,表达式序列的值是最后一个表达式的值。

21. 函数引用(与C中的函数指针相似):

方法一:fun LocalFunc/Arity

方法二:fun Mod:RemoteFunc/Arity

如:lists:map(fun square/1, L). 再如:lists:map(fun x1:square/1, L).

22. 包 含文件:-include(Filename),这个语法可以包含扩展名为.hrl的包含文件。FileName应该包含一个绝对或者相对路径。 -include_lib(name),这个语法可以引入库的包含文件,如:-include_lib("kernel/include /file.hrl").

23. 列表操作符++和--:

A++B意味着把A和B加起来,把B附加到A上生成一个新的列表。

A--B从列表A中删除列表B。删除的意思是B中的所有元素都要从A中删除。注意,如果符号X在B中出现K次,那么在A中只会按顺序删除K个X。

++也可以用在模式匹配中。如:f("begin"++T) ->...,这个模式会被扩展为[$b, $e, $g, $i, $n|T]

24. 宏:

宏定义的语法:

-define(Constant, Replacement).

-define(Func(Var1, Var2, ..., VarN), Replacement).

    在代码中使用宏:?MacroName

25. 系统预定义宏:
    ?FILE 扩展为当前文件名
    ?MODULE 扩展为当前模块名
    ?LINE 扩展为当前行

26. 宏的流程控制
    -undef(Macro).    取消宏定义,在这个语句后不能再调用这个宏
    -ifdef(Macro).    只有Macro被定义后,才对该行以下的代码进行运算。
    -ifndef(Macro).       只有在不定义Macro的情况下,才对该行以下的代码进行运算。
    -else.    只能在ifdef或ifndef后出现
    -endif.    标记if的结束。
27. c(m1, Options)命令可以在编译代码时向编译器传输一些选项,如c(test, {d, debug}).在编译test.erl时定义一上debug宏,这样在代码中的ifdef(debug)就为true了。
28. 模式匹配操作符
    func1([{tag, {one, A}=Z1, B}=Z2|T}]) ->
            f(..., Z2, ...),
            g(..., Z1, ...),
        ...
    其中Z1相当于{one, A}, 而Z2相当于{tag, {one, A}, B}
29. 数值类型:erlang中的数值类型包括整型和浮点型
    三种表示整数的方法:
    (1). 传统语法:12, -234
    (2). K进制语法:K#Digits, 2#00101010, 16#af6bfa23
    (3). $语法:$C代表C的ASCII码,也可以是转义字符,如:$/n.
    浮点数:1.0, 3.14159, -2.3e+6, 23.56E-27
    erlang中可表示的浮点数的范围是-10的323次幂~10的308次幂。
30. 操作符优先级:
    :
    #
    (unary)+, (unary)-, bnot, not
    /, *, div, re, band, and
    +, -, bor, bxor, bsl, bsr, or, xor
    ++, --
    ==, /=, =<, >=, >, =:=, =/=
    andalso
    orelse
31. 进程字典:erlang的每一个进程都有自己的私有数据存储,叫做进程字典。进程字典是由一系列键值对组成的关联数组,像C++的map
    可以使用下面的BIF来操纵进程字典:
    @spec put(Key, Value) -> OldValue.    %% 如果没有之前关联过的值,则返回原子undefined。
    @spec get(Key) -> Value.        %% 如果没有这个Key,则返回原子undefined。
    @spec get() -> [{Key, Value}].
    @spec get_keys(Value) -> [Key].
    @spec erase(Key) -> Value.        %% 如果没有这个Key,则返回原子undefined。
    @spec erase() -> [{Key, Value}]
    尽是避免使用进程字典,因为进程字典不是非破坏性赋值。
    有一种情况可以,那就是使用进程字典来存储“一次性写入”变量。如果一个键与一个值仅绑定一次而且不再修改。
32. 引用:引用是一个全局唯一的Erlang值,可以用BIF make_ref()来创建引用。好像有点像全局唯一标识。
33. 短路布尔表达式:
    Expr1 orelse Expr2    %% 如果Expr1结果为false,才会对Expr2求值
    Expr1 andalso Expr2    %% 如果Expr1结果为true,才会对Expr2求值

    在A or B和A and B中,无论什么情况A和B都会被求值。
34. 比较表达式
    X>Y
    X<Y
    X=<Y    %% X小于等于Y, 这个很奇怪
    X>=Y
    X == Y    %% 用于数值类型
    X /= Y    %% 用于数值类型
    X =:= Y    %% X全等于Y
    X =/= Y    %% X不全等于Y
    不同的类型也能比较
    number<atom<reference<fun<port<pid<tuple<list<binary
35. ==和/=在比较整数和浮点数时可以对两边的数值进行类型转换。而=:=和=/=确不会。
    如:1.0 == 1(true) 1.0 =:= 1(false)
    另外,由此产生的一个问题是,如果我们定义了一个函数F=fun(12)->...end. 那么当我们调用F(12.0)时会出错。
36. 下划线变量:如果一个变量只出现一次,以后没有被使用过,编译时会出现警告。如果不想看到这个警告的话,可以将其命令为一个以下划线开头的变量_VarName.

你可能感兴趣的:(《Erlang程序设计》学习笔记-第5章 顺序型编程进阶)