Erlang是被設計來用在電信設備中的,這意味着須要處理大量的二進制數據。也正由於如此,Erlang把binary和binary string提高到了一個至關高的位置,提供了極爲豐富的操做機制。固然,豐富意味着多,多了可能會有些眼花繚亂,有人給的建議是,若是感受搞不定怎麼處理bit串,能夠先在shell裏面慢慢的試出本身要的表達,而後copy到程序中去。shell
一、下面例子形象展現了bit 流的組裝:網絡
> Color = 16#F09A29. 15768105 > Pixel1 = <<Color>>. <<")">> > Pixel2 = <<Color:16>>. <<154,41>> > Pixel3 = <<Color:24>>. <<240,154,41>>
咱們能夠看到:ide
1)在定義Pixel1時,咱們沒有給bit串指定長度,因此,它默認是一個byte,而0x29剛好是字符「)」;this
2)在定義Pixel2時,咱們指定bit串的長度是16,咱們看到他把後面16位轉換爲bit串,即咱們看到的兩個8bit長數字;atom
3)在定義Pixel3時,咱們指定bit串的長度是24,而後咱們就獲得了完整的bit串-3個8bit長的bit串。spa
二、用patten matching 對bit流進行拆分,具體以下:設計
1> Pixels = <<213,45,132,4,76,32,76,0,0,234,32,15>>. <<213,45,132,4,76,32,76,0,0,234,32,15>> 2> <<Pix1,Pix2,Pix3,Pix4>> = Pixels. ** exception error: no match of right hand side value <<213,45,132,4,76,32,76,0,0,234,32,15>> 3> <<Pix1:24,Pix2:24,Pix3:24,Pix4:24>> = Pixels. <<213,45,132,4,76,32,76,0,0,234,32,15>> 4> <<Pix1:24>>. <<213,45,132>>
這裏的操做有:code
1)表達式2並無指定patten matching的長度,Erlang默認按8bit處理,因此,4x8=32bit,與右邊的4x24長度不匹配。即,彈出的error:no match。blog
2)表達式3咱們指定了24-24-24-24這樣的長度,與右邊匹配,因此取出了<<Pix1:24>>=<<213,45,132>>.內存
另外,若是咱們只去第一個8位,是不必去拆開整個bit串的,Erlang給咱們準備了一個語法糖:
> <<R:8,Rest/binary>> = Pixels. <<213,45,132,4,76,32,76,0,0,234,32,15>> > R. 213
三、Erlang中bit串的描述方式包括:
咱們來具體看看這些是什麼。其中,TypeSpecifierList有「Unit:xxx」, 「Type」,「Signedness」還有「Endianness」幾種,使用時用(-)來隔開:
-Value. 這個bit串表明的這個數值爲多少。
-Size. 這一bit串佔用了多少Unit。
-Unit:xxx. xxx 取值範圍是1-255,表示每Unit佔的bit數。Size x Unit爲該數實際佔用的bit數。
-Type. 這個屬性描述了bit流是按什麼方式組織的,有integer,float,binary(bytes),bitstring(bits),utf8,utf16, and utf32。若是沒有指定格式,Erlang會默認認爲他是integer類型。其中integer,float,binary默認的一個unit佔1bit,咱們能夠用Unit來指定各個type每一個unit佔用幾個bit;這僅僅表示它申請了這麼多內存,可是存放時僅僅是在前面插了一些0。例如,
> <<8:8/unit:2>> == <<8:16>>. true > <<123456:16/unit:2>>. <<0,1,226,64>> > <<123456:32>>. <<0,1,226,64>>
如上,「16個unit,每一個unit佔2bit」與「32個unit,每一個unit佔1bit」表示的是一樣多的bit數。
-Signedness.這一屬性只有兩個選項signed和unsigned,默認是unsigned。同時,只有bit串是integer類型的時候,咱們纔會考慮這一屬性。
-Endianness.可能的值有big,little,native,默認是big,並且在標準的網絡協議應用中都是big ending。同時,大小端只有在數據是integer,utf16,utf32,或者是float時有用。native取決於cpu運行時使用大端仍是小端。
舉例:
1> <<Y:4/unit:8>> = <<72,0,0,0>>. <<72,0,0,0>> 2> Y. 1207959552 3> <<X:4/little-unit:8>> = <<72,0,0,0>>. <<72,0,0,0>> 4> X. 72
上面的代碼中:
-1中,這個bit串是integer型的,它的值爲Y,Size爲4,每一個Unit爲8位。那麼,右邊的bit串表明一個integer的話,這個integer的值應該是1207959552。
-3中,這個bit串一樣是integer型的,它的值爲X,Size爲4,每一個Unit爲8位;可是,這個bit串是小端存放的。那麼,右邊的bit串若是表明一個小端存放的integer的話,這個integer的值應該是72。
四、bit串的運算方式有:左移(bsl,bit shift left),右移(bsr,bit shift right),按位與(band),按位或(bor),按位亦或(bxor),按位取反(bnot)。
五、binary strings處理字符串要比Lists更加的節省空間,主要是Lists事實上更像是鏈表,而binary更像是array(a tightly packed block of memory)。因此,在不須要對字符串進行太多處理,或者是內存比較敏感的狀況下,你們更樂意用binary string。
ps:儘管binary string是種輕量級的方案,可是,咱們仍是應該儘可能避免使用它來作tag。這是由於,沒有什麼比atom更適合作tag了,使用其它就多餘了。
> <<"this is a binary string!">>.
<<"this is a binary string!">>
六、binary comprehension是和Lists comprehension同樣的存在。只不過,咱們在描述元素屬於某個bit串時,使用的符號由"<-"變成了「<=」;描述的目標是一個bit串時,咱們要把最外面的「[ ]」,一樣換成"<<>>"。具體能夠看下面兩個例子:
> Pixels = <<213,45,132,64,76,32,76,0,0,234,32,15>>. <<213,45,132,64,76,32,76,0,0,234,32,15>> > RGB = [ {R,G,B}||<<R:8,G:8,B:8>> <= Pixels ]. [{213,45,132},{64,76,32},{76,0,0},{234,32,15}]
這樣,咱們輕鬆的把Pixels數據轉化爲RGB tuple的lists。注意「<<R:8,G:8,B:8>> <= Pixels」一句,8-8-8只有24個bit,而Pixels有12 X 8個bit,因此,這裏處理的時候,是按描述循環取了四次。
另外一個例子偏偏相反:
> << <<R:8,G:8,B:8>> || {R,G,B} <- RGB >>.
<<213,45,132,64,76,32,76,0,0,234,32,15>>
ps:咱們要注意generator返回的bit串是什麼類型,忽略的話可能會出錯。好比在下面例子中:
> << <<Bin>> || Bin <- [<<3,7,5,4,7>>]>>. ** exception error: bad argument > << <<Bin/binary>> || Bin <- [<<3,7,5,4,7>>]>>. <<3,7,5,4,7>>
首先應該注意到,[<<3,7,5,4,7>>]是構建了一lists,其中只有一個元素,即,一個bit串。
上面的代碼先是定義bit串<<Bin>>,Value的類型默認是integer,即Bin是一個integer類型的數,而後嘗試把generator產生的bit串賦值給Bin...等等,這就是bad argument的根源所在。
第二次,咱們聲明Bin的Value是binary類型的,因此,咱們成功的接收了這個bit串。
更多關於bit串的處理,參見: http://user.it.uu.se/~pergu/papers/erlang05.pdf