處理二進位資料有時候會有點棘手,所以 Gleam 提供了BitArray型別,以及搭配的語法,讓你建構二進位資料,也能对它進行模式匹配。
位元陣列字面值是用<<>>語法定義的。定義位元陣列字面值時,會以區段為單位來定義。每個區段都有一個值和一個標註,兩者以:分隔。標註用來指定要用幾個位元來編碼這個值,也可以完全省略,此時會預設為 8 位元的整數值。
// This defines a bit array with three segments of a single bit each
<<0:1, 1:1, 0:1>>
// This defines a bit array with three segments of 8 bits each
<<0, 1, 0>>
把型別寫成:1是:size(1)的簡寫。如果位元大小來自變數,就必須使用較長的語法。
let segment_size = 1
<<0:size(segment_size), 1:size(segment_size), 0:size(segment_size)>>
撰寫二進位整數字面值時,可以在字面值前面加上0b,直接以二進位表示法來寫。要注意的是,在測試或你的程式中印出時,它們會以十進位數字顯示。
<<0b1011:4>> == <<11:4>>
// -> True
如果區段的值超出該區段型別的容量,就會從左邊截斷。
<<0b1011:3>> == <<0b0011:3>>
// -> True
使用位元陣列語法,你可以同時在既有位元陣列的前面加入資料,也在後面附加資料。既有的位元陣列必須使用:bits標註。
let value = <<0b110:3, 0b001:3>>
let new_value = <<0b011:3, value:bits, 0b000:3>>
// -> <<120, 8:size(4)>>
我們可以用這個語法,串接存在變數裡的位元陣列。串接兩個大小不固定的位元陣列時,必須使用:bits標註。
let first = <<0b110:3>>
let second = <<0b001:3>>
let concatenated = <<first:bits, second:bits>>
// -> <<49:size(6)>>
也可以透過模式匹配,從位元陣列中取出值。你必須知道每個想捕捉的片段有多少位元,只有一個例外:可以用:bits標註,對大小未知的位元陣列進行模式匹配,但這只能用在最後一個片段。
let assert <<value:4, rest:bits>> = <<0b01101001:8>>
value == 0b0110
// -> true
位元陣列印出來的格式,可能和建立它時所用的格式不同。這在學習位元陣列時經常造成困惑。
預設情況下,位元陣列會以 8 位元(一個位元組)的片段來顯示,即使你建立它時用的片段大小不同也一樣。
<<2011:11>>
// -> <<251, 3:size(3)>>
如果你建立的位元陣列代表一段可列印的 UTF-8 編碼字串,當編譯目標是 Erlang 時,使用echo keyword可能會將它顯示為字串。這是因為 Gleam 在內部表示字串的實作細節所致。
<<>>
// -> ""
<<65, 66, 67>>
// -> "ABC"