二进制型(binary)是一种数据结构,当二进制型里的位数都会是8
的整数倍时,对应一个字节串。当位数不是8
的整数倍,则称这段数据为位串(bitstring)。
二进制型的编写和打印形式是双小于号与双大于号之间的一列整数或字符串:
1> <<19,88,20>>.
<<19,88,20>>
2> <<"hello">>.
<<"hello">>
3> <<49,50,51>>.
<<"123">>
4> <<99,97,116>>.
<<"cat">>
在二进制型里使用整数时,它们必须属于0
至255
这个范围。
二进制型<<"cat">>
是<<99,97,116>>
的简写形式,这个二进制型是由字符串里这些字符的ASCII
编码组成的。
和字符串类似,如果某个二进制型的内容是可打印的字符串,shell就会将这个二进制型打印成字符串,否则就打印成一列整数。
可以用内置函数和位语法来构建二进制型或提取它里面的元素。
1. 内置函数
list_to_binary(L) -> B
list_to_binary
返回一个二进制型,它是通过把io列表(iolist)L
里的所有元素压扁后形成的(压扁的意思是移除列表里所有的括号)。io列表本身是循环定义的,它是指一个列表所包含的元素是0…255的整数、二进制型或者其他io列表。
5> list_to_binary([999,123]). %% 999超出范围0~255
** exception error: bad argument
in function list_to_binary/1
called as list_to_binary([999,123])
6> list_to_binary([<<"abc">>, 123, <<1,2,3>>]).
<<97,98,99,123,1,2,3>>
split_binary(Bin, Pos) -> {Bin1, Bin2}
这个函数在Pos
处把二进制型Bin
一分为二。
7> split_binary(<<1,2,3,4,5,6,7,8>>, 3).
{<<1,2,3>>,<<4,5,6,7,8>>}
-
term_to_binary(Term) -> Bin
把任何Erlang数据类型转换成一个二进制型。 -
binary_to_term(Bin) -> Term
term_to_binary
的逆操作。
8> term_to_binary({abc, [1,2,3]}).
<<131,104,2,100,0,3,97,98,99,107,0,3,1,2,3>>
9> binary_to_term(<<131,104,2,100,0,3,97,98,99,107,0,3,1,2,3>>).
{abc,[1,2,3]}
byte_size(Bin) -> Size
10> byte_size(<<1,2,3>>).
3
11> byte_size(<<>>).
0
2. 位语法
位语法是一种表示法,用于从二进制数据里提取或加入单独的位或者位串。
它们的形式如下:
<<>>
<<E1, E2, ..., En>>
每个Ei
元素都标识出二进制型或位串里的一个片段。单个Ei
元素可以有4种形式。
Ei = Value |
Value:Size |
Value/TypeSpecifierList |
Value:Size/TypeSpecifierList
如果表达式的总位数是8
的整数倍,就会构建一个二进制型,否则构建一个位串。
构建二进制型时,Value
必须是已绑定变量、字符串,或是能得出整数、浮点数或二进制型的表达式。用于模式匹配操作时,Value
可以是绑定或未绑定的变量、整数、字符串、浮点数或二进制型。
Size
的值指明了片段的大小。它的默认值取决于不同的数据类型,对整数来说是8
,浮点数则是64
,如果是二进制型就是该二进制型的大小。在模式匹配里,默认值只对最后那个元素有效。如果未指定片段的大小,就会采用默认值。
TypeSpecifierList
(类型指定列表)是一个用连字符分隔的列表,形式为End-Sign-Type-Unit
。前面这些项中的任何一个都可以被省略,各个项也可以按任意顺序排列。如果省略了某一项,系统就会使用它的默认值。
End
可以是big
|little
|native
它指定机器的字节顺序。native
是指在运行时根据机器的CPU
来确定。默认值是big
,也就是网络字节顺序(network byte order)。
12> {<<16#12345678:32/big>>,<<16#12345678:32/little>>,<<16#12345678:32/native>>,<<16#12345678:32>>}. %% 16# 表示十六进制
{<<18,52,86,120>>,
<<120,86,52,18>>,
<<120,86,52,18>>,
<<18,52,86,120>>}
-
sign
可以是signed
|unsigned
这个参数只用于模式匹配。默认值是unsigned
。 -
Type
可以是integer
|float
|binary
|bitstring
|bits
|utf8
|utf16
|utf32
默认值是integer
。 -
Unit
的写法是unit:1|2|...|256
integer
、float
和bitstring
的Unit
默认值是1
,binary
则是8
。utf8
、utf16
和utf32
类型无需提供值。
13> <<49:8>>.
<<"1">>
14> <<49:8/unit:1>>.
<<"1">>
15> <<49:8/unit:2>>.
<<0,49>>
16> <<49:7>>.
<<49:7>>
17> <<49:7/unit:1>>.
<<49:7>>
18> <<49:7/unit:2>>.
<<0,49:6>>
一个片段的总长度是Size x Unit``bit
。binary
类型的片段长度必须是8
的整数倍。
3. 位推导
位推导和二进制型的关系就像列表推导和列表的关系一样。列表推导遍历列表并返回列表。位推导遍历二进制型并生成列表或二进制型。
19> B = <<16#5f>>.
<<"_">> %% 16#5f是一个十六进制的常量。shell把它打印成了<<"_">>,因为16#5f是_字符的ASCII编码。
20> [X || <<X:1>> <= B]. %% <<<X:1>>是一个模式,代表1位。
[0,1,0,1,1,1,1,1]
21> [X || <<X:2>> <= B].
[1,1,3,3]
22> << <<X>> || <<X:1>> <= B >>.
<<0,1,0,1,1,1,1,1>>
23> [X || <<X:1>> <- B]. %% 注意是 <= 而不是 <-
** exception error: bad generator <<"_">>
20与22的区别在于20构建了一个包含这些位的列表,而22构建了一个二进制型。
4. 实例
- 编写一个函数来反转某个二进制型里的字节顺序。
reverse_bitstring_by_byte(BitString) ->
ByteList = [Byte || <<Byte:8>> <= BitString],
ReverseByteList = lists:reverse(ByteList),
ReverseBitString = list_to_binary(ReverseByteList),
ReverseBitString.
- 编写一个函数来反转某个二进制型所包含的位。
reverse_bitstring_by_bit(BitString) ->
BitList = [Bit || <<Bit:1>> <= BitString],
ReverseBitList = lists:reverse(BitList),
ReverseBitString = list_to_binary(ReverseBitList),
ReverseBitString1 = << <<Bit:1>> || <<Bit:8>> <= ReverseBitString>>,
ReverseBitString1.
注:本博客为通过《Erlang程序设计 第二版》学习Erlang时所做的笔记。学习更详细的内容,建议直接阅读《Erlang程序设计 第二版》。