入門者向けです(自分含む)。Elixirのチュートリアル読み進めつつまとめてます。
Keyword list
- 特定の条件のtupleのリストはkeyword list として扱われる
- tupleの要素数が2
- 1つ目の要素が atom
- listの特徴を受け継いでいるので、長くなればなるほどサイズ取得時や、後方の要素を取得する際のパフォーマンスが落ちる。ElixirのListは個々の要素が値と次の要素のポインタを保持している構造になっているため。
iex> list = [{:a, 1}, {:b, 2}]
[a: 1, b: 2]
# アクセスするときはキー名を指定できる。
iex> list[:a]
1
# 直接書いても通る
iex> list = [a: 1, b: 2]
# 一つ目の要素がatomでない場合はtupleのlistとして扱われる
iex> list = [{"a", 1}, {"b", 2}]
[{"a", 1}, {"b", 2}]
# 要素数が異なる場合はtupleのlistとして扱われる
iex>list = [{:a, 1}, {:b, 2, 4}]
[{:a, 1}, {:b, 2, 4}]
# キーの重複は許容される
iex> list = [{:a, 1}, {:a, 2}]
[a: 1, a: 2]
# アクセスするとListの先頭から先に見つかった要素が表示される。
iex> list[:a]
1
# 通常のListと同じ操作が使える
iex> list = [{:a, 1}, {:b, 2}]
[a: 1, b: 2]
iex> list ++ [c: 3]
[a: 1, b: 2, c: 3]
iex> [a: 0] ++ list
[a: 0, a: 1, b: 2]
Map
- key -value のデータを扱いたいときはMapを使う。
- %{ } で囲む
- 関数の引数でMapを使ったパターンマッチを使うと便利
- 割と最近導入された仕組みで小さいMapを扱うのに適している。容量の大きなKeyが必要になるデータはHashDict を使ったほうが性能が良いらしい。
iex> map = %{:a => 1, :b => 2}
%{a: 1, b: 2}
# キー名を指定してアクセスできる
iex> map[:a]
1
# 存在しないキーはnilが返る
iex> map[:c]
nil
# キーのデータ型が統一されていなくても通る
iex> map = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}
# キーの重複は許可されず、後勝ち
iex> map = %{:a => 1, :a => 2}
%{a: 2}
# valiableをキーに指定することはできない
iex> key = :a
:a
iex> map = %{key => 1}
** (CompileError) iex:61: illegal use of variable key in map key
(elixir) src/elixir_translator.erl:344: :elixir_translator.translate_arg/3
(elixir) src/elixir_map.erl:154: anonymous fn/7 in :elixir_map.translate_map/4
(stdlib) lists.erl:1352: :lists.mapfoldl/3
(elixir) src/elixir_map.erl:153: :elixir_map.translate_map/4
(elixir) src/elixir_translator.erl:17: :elixir_translator.translate/2
# mapにvaliableでアクセスすることはできる
iex> map[key]
1
# mapを更新する。immutableなので更新後の値を再利用したいときは別の変数に束縛しとく。
iex> %{map | :a => 2}
%{2 => :b, :a => 2}
# 更新するときに存在しないキーを指定すると例外
iex> %{map | :c => 3}
** (ArgumentError) argument error
(stdlib) :maps.update(:c, 3, %{a: 1, b: 2})
(stdlib) erl_eval.erl:255: anonymous fn/2 in :erl_eval.expr/5
(stdlib) lists.erl:1261: :lists.foldl/3
- パターンマッチ
iex> map = %{:a => 1, :b => 2, :c => 3}
# 必ずマッチする
iex> %{} = map
%{a: 1, b: 2, c: 3}
# 部分的にマッチする
iex> %{:b => 2} = map
%{a: 1, b: 2, c: 3}
# 値を束縛する
iex> %{:a => a, :b => 2, :c => c} = map
%{a: 1, b: 2, c: 3}
iex> a
1
iex> c
3
# マッチしないと例外
iex> %{:a => 2} = map
** (MatchError) no match of right hand side value: %{a: 1, b: 2, c: 3}
Dicts
- Keyword list と Map は dictionaryが実装されている(behaviourと呼ばれてるらしい)ので Dict moduleのメソッドが使える