読者です 読者をやめる 読者になる 読者になる

OTPを勉強した(Agent)

Elixir

OTP周りがイマイチわからなかったので公式ガイドをなぞりつつこの機会に勉強してみた

備忘録がてらかく

Agent

Agentはelixirのstate管理を簡易的に行ってくれるmodule

基本的にはAgent.start_link, Agent.get, Agent.putといったビルトインモジュールをラップして使うっぽい

流れは以下

  1. Agent.start_linkでプロセスを作成する
  2. このガイドではstart_link時にfn -> %{} endのようにからのMapを作成したプロセスに与えている
  3. Agent.putでプロセス内にデータを入れる。
  4. start_linkでMapを与えたので、データを入れるときもMap.put/3で入れる
  5. Agent.getでプロセス内のデータを参照
  6. Mapのkeyからvalueを取得
  7. Agent.deleteでプロセス内のデータを削除
  8. 第二引数で与えたkeyをvalueもろとも削除

公式のガイドに

Agent - Simple wrappers around state.

と書いてあるだけあって、非常にシンプルだった

サンプルコード

以下公式ガイドのコード

defmodule KV.Bucket do
  @doc """
  Starts a new bucket.
  """
  def start_link do
    Agent.start_link(fn -> %{} end)
  end

  @doc """
  Gets a value from the `bucket` by `key`.
  """
  def get(bucket, key) do
    Agent.get(bucket, &Map.get(&1, key))
  end

  @doc """
  Puts the `value` for the given `key` in the `bucket`.
  """
  def put(bucket, key, value) do
    Agent.update(bucket, &Map.put(&1, key, value))
  end

  @doc """
  Deletes `key` from `bucket`.

  Returns the current value of `key`, if `key` exists.
  """
  def delete(bucket, key) do
    Agent.get_and_update(bucket, &Map.pop(&1, key))
  end
end

使うときは以下のように

iex(1)> {:ok, bucket} = KV.Bucket.start_link
{:ok, #PID<0.121.0>}
iex(2)> KV.Bucket.put(bucket, :foo, :bar)
:ok
iex(3)> KV.Bucket.get(bucket, :foo)
:bar
iex(4)> KV.Bucket.delete(bucket, :foo)
:bar
iex(5)> KV.Bucket.get(bucket, :foo)
nil

その他

elixirではfunctionの先頭に&をつけることで、関数を変数に格納できる

named function

iex(1)> func = &Map.get/2
&Map.get/2
iex(2)> func.(%{foo: "bar"}, :foo)
"bar"

anonymous function

iex(1)> func = &(&1 + 1)
#Function<6.52032458/1 in :erl_eval.expr/5>
iex(2)> func.(2)
3

イメージとしては丁度JavaScriptの関数と同じような印象

const func = (obj, key) => { return obj[key]; }
func({foo: "bar"}, "foo")
// 'huga'

所感

  • phoenixでOTP使うときってどんなときなのかがイマイチ不明だ

参考