[Elixir] Referenceの作り方


この記事は Elixir その2 Advent Calendar 2020 20日目です。

前日は、「[Elixir] Supervisor child_spec」でした。

はじめに

さて、今年になってナウでヤングでcoolな「Nerves」というIoTフレームワークに出会い、今どきのカッコいい電子工作を楽しみながら、Elixirの勉強をしています。ラズパイにLEDを接続して点灯、点滅させたりするのですが、その際に使用するライブラリーがReferenceを戻り値として返してきます。
しばらくの間は、「参照」であるとの理解で問題なくコードをかけてましたが、テストコードを書いているときにReferenceを作りたくなったので、作り方を調べました。

結論

iex> make_ref()
#Reference<0.1816055995.4047503364.216777>

どこでReferenceに遭遇したか

LEDを接続するGPIO(汎用入出力)を操作するために使用するのがelixir-circuits/circuits_gpioです。
まず最初に行うのが、GPIOへの参照を取得することです。そこでReferenceが登場します。

iex> {:ok, gpio_pin} = Circuits.GPIO.open(12, :output)
{:ok, #Reference<0.2184343048.2460614673.37929>}

そのReferenceを使用して、GPIOピンのON/OFF操作をします。

iex> Circuits.GPIO.write(gpio_pin, 1)
:ok

Circuits.GPIOソースコードを読んで見る

コードの量は思ったより少ないです。ほとんどCで書かれています。
詳しくは僕にはよく理解できませんが、ErlangのNative Implemented Functions (NIFs)という機能を利用してCで書かれた関数を呼び出せるようになってます。ここのenif_make_resource関数がReferenceを取得しています。enif_make_resourceはオブジェクトを作るときに使用されるようです。結局よくわかりませんが、こういうものがあると分かったのでいい機会でした。

Reference型とは

ElixirのドキュメントをよくみるとのBuilt-in typesひとつとして挙げられてます。

a unique value in the runtime system, created with make_ref/0

更に調べてみると、ErlangにReferenceがあるので、これだと思います。

References are erlang objects with exactly two properties:
- They can be created by a program (using make_ref/0), and,
- They can be compared for equality.

Erlangオブジェクトに紐付けされたUUIDのようなものってことですかね。

Referenceのつくりかた

Kernel.html#make_ref/0で生成可能。

iex> make_ref()
#Reference<0.1816055995.4047503364.216777>

# 詳しくは
iex> h make_ref

IEx内に限り、ヘルパー関数refを使用可能。

iex> ref("0.1.2.3")
#Reference<0.1.2.3>

iex> ref(0, 1, 2, 3)
#Reference<0.1.2.3>

# 詳しくは
iex> h ref

さいごに

因みにテストコードでやりたかったのはこんな感じにハードウエアのモックに対してスタブ関数を定義することです。

#NervesJP Advent Calendar 2020でも、パルス幅変調 (PWM) Lチカについて投稿しました。Nerves楽しいですよ。

今後更に新しいことを学んだら随時内容も更新していこうと思います。


明日は、おなじみの@torifukukaiouさんpresents「1260 (Elixir 1.11.2-otp-23)」です。引き続き、Elixirを楽しみましょう。

Happy coding!