ZEAM開発ログ v.0.4.5 ビット列について調べてみる

ZACKY こと山崎進です。

今回は少し脱線して，Elixir のビット列について調べてみます。将来C言語との特に構造体によるインタフェースを考える上で重要になってきます。

ところで 菊池 豊さん @kikuyuta の記事を書くペースが半端ないですね！ 今回の記事でささやかながら対抗してみたいと思いますw

[「ZEAM開発ログ 目次」はこちら](https://qiita.com/zacky1972/items/70593ab2b70d192813df)

# さっそく iex の実行結果を見てみましょう

```elixir
$ iex
Erlang/OTP 21 [erts-10.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> bs = << 3 :: size(2) >>
<<3::size(2)>>
iex(2)> is_bitstring(bs)
true
iex(3)> is_binary(bs) 
false
iex(4)> byte_size(bs)
1
iex(5)> bs = << 0 :: size(2), 1 :: size(2), 2 :: size(2), 3 :: size(2)>>
"\e"
iex(6)> is_bitstring(bs)
true
iex(7)> is_binary(bs)
true
iex(8)> byte_size(bs)
1
iex(9)> << head :: size(2), tail :: bitstring >> = bs
"\e"
iex(10)> head
0
iex(11)> tail
<<27::size(6)>>
iex(12)> << head :: size(2), tail :: bitstring >> = tail
<<27::size(6)>>
iex(13)> head                                           
1
iex(14)> tail                                           
<<11::size(4)>>
iex(15)> << head :: size(2), tail :: bitstring >> = tail
<<11::size(4)>>
iex(16)> head                                           
2
iex(17)> tail                                           
<<3::size(2)>>
iex(18)> << head :: size(2), tail :: bitstring >> = tail
<<3::size(2)>>
iex(19)> head                                           
3
iex(20)> tail                                           
""
iex(21)> << head :: size(2), tail :: bitstring >> = tail
** (MatchError) no match of right hand side value: ""
    (stdlib) erl_eval.erl:450: :erl_eval.expr/5
    (iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:230: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:208: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
    (iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4
```

何をしたか解説します。

```elixir
iex(1)> bs = << 3 :: size(2) >>
<<3::size(2)>>
```

10進数で3，2進数で11の値を持つ2ビット列 `bs` を定義してみました。

```elixir
iex(2)> is_bitstring(bs)
true
iex(3)> is_binary(bs) 
false
iex(4)> byte_size(bs)
1
```

ビット列は `is_bitstring` で `true`，`is_binary` で `false` になります。`byte_size` は1バイトです。

```elixir
iex(5)> bs = << 0 :: size(2), 1 :: size(2), 2 :: size(2), 3 :: size(2)>>
"\e"
```

それぞれ 0, 1, 2, 3 の2ビットの値を4つ持つビット列 `bs` を定義してみました。2進数で 00011011，16進数で1bですから，UTF-8 で ESC "\e" になります。

```elixir
iex(6)> is_bitstring(bs)
true
iex(7)> is_binary(bs)
true
iex(8)> byte_size(bs)
1
```

8ビット充足すると `is_binary` も true になります。

```elixir

iex(9)> << head :: size(2), tail :: bitstring >> = bs
"\e"
iex(10)> head
0
iex(11)> tail
<<27::size(6)>>
```

ビット列もリストのように `head` と `tail` に分解できます。これはなかなか強力な操作です。

```elixir
iex(12)> << head :: size(2), tail :: bitstring >> = tail
<<27::size(6)>>
iex(13)> head                                           
1
iex(14)> tail                                           
<<11::size(4)>>
iex(15)> << head :: size(2), tail :: bitstring >> = tail
<<11::size(4)>>
iex(16)> head                                           
2
iex(17)> tail                                           
<<3::size(2)>>
iex(18)> << head :: size(2), tail :: bitstring >> = tail
<<3::size(2)>>
iex(19)> head                                           
3
iex(20)> tail                                           
""
```

空になるまで分解してみました。

```elixir
iex(20)> tail                                           
""
iex(21)> << head :: size(2), tail :: bitstring >> = tail
** (MatchError) no match of right hand side value: ""
    (stdlib) erl_eval.erl:450: :erl_eval.expr/5
    (iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:230: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:208: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
    (iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4
```

空になってなおパターンマッチしようとすると `MatchError` になります。

次回ですが， @Tsuyoshi84 さんが素敵な記事[「OKを使ってElixirの :ok, :error タプルをエレガントに処理」](https://qiita.com/Tsuyoshi84/items/5a020ef185b094778d92)を書いてくれたので，それに刺激を受けて[「ZEAM開発ログ v.0.4.6 OKを使ってNIFのエラー処理をエレガントに書いてみる」](https://qiita.com/zacky1972/items/54ce88214c9a8b10d645)をお送りします。お楽しみに！


:stars::stars::stars:<b>　お知らせ：Elixirもくもく会（リモート参加OK、入門トラック有）を9月28日に開催します　</b>:stars::stars::stars:

[<b>「fukuoka.ex#14：Elixir／Phoenixもくもく会～入門もあるよ」</b>](https://fukuokaex.connpass.com/event/100659/)を2018年9月28日金曜日に開催します

前回は，ゲリラ的に募った「Zoomによるリモート参加」を，今回から正式に受け付けるようになりましたので，福岡以外の首都圏や地方からでも参加できます（申し込みいただいたら、追ってZoom URLをconnpassメールでお送りします）

また，これまではElixir／Phoenix経験者を対象とした，もくもく会オンリーでしたが，今回から，入門者トラックも併設し，fukuoka.exアドバイザーズ／キャストに質問できるようにアップグレードしました

私，山崎も参加します！ この記事の延長線上のものを作ろうと思っています。

お申込みはコチラから
https://fukuokaex.connpass.com/event/100659/
[![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/3f0fbb56-e5e8-2c4d-7c62-1b0b311d6d02.png)](https://fukuokaex.connpass.com/event/100659/)