- 更新
2014-03-05
- バージョン
0.1.1
- 作者
@voluntas
- URL
この資料は 17 系がリリースされる前の資料のため色々古いです
18.0 がリリースされたタイミングで更新予定です
Erlang/OTP 17.0 で導入される Map を触ってみます。
定義はこちら http://www.erlang.org/eeps/eep-0043.html
- Map comprehension syntax
- Accessing a single value
Map が実装されている Erlang/OTP 17RC2 を使います
頑張ってコンパイルして下さい
文法は、大きく二つに分かれます。Put と Update です。
Put:
#{ key => val }
Update:
#{ key := val }
Put と Update の違いですが、Put は存在しないキーでも追記可能です。Update の := は存在しないキーに対して実行するとちゃんとクラッシュしてくれます。
以下の例は Person という map に対して値を入れて行っています。 => の場合は特に問題なく gender という key / value を入れられますか := の場合は 存在しない ものを 更新 しようとしているためクラッシュします。
Erlang/OTP 17 [RELEASE CANDIDATE 2] [erts-6.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [kernel-poll:false] [dtrace]
Eshell V6.0 (abort with ^G)
1> Person = #{name => spam, age => 10}.
#{age => 10,name => spam}
2> Person#{age => 20}.
#{age => 20,name => spam}
3> Person#{age := 15}.
#{age => 15,name => spam}
4> Person#{gender => male}.
#{age => 10,gender => male,name => spam}
5> Person#{gender := male}.
** exception error: bad argument
in function maps:update/3
called as maps:update(gender,male,#{age => 10,name => spam})
in call from erl_eval:'-expr/5-fun-0-'/2 (erl_eval.erl, line 249)
in call from lists:foldl/3 (lists.erl, line 1261)
実はこの Put と Update ですが、maps モジュールでも同様のことが出来ます。
1> Person = maps:new().
#{}
2> Person2 = maps:put(name, spam, Person).
#{name => spam}
3> Person3 = maps:put(age, 10, Person2).
#{age => 10,name => spam}
4> maps:put(age, 20, Person3).
#{age => 20,name => spam}
5> maps:update(age, 15, Person3).
#{age => 15,name => spam}
6> maps:put(gender, male, Person3).
#{age => 10,gender => male,name => spam}
7> maps:update(gender, male, Person3).
** exception error: bad argument
in function maps:update/3
called as maps:update(gender,male,#{age => 10,name => spam})
Map でももちろんパターンマッチが出来ます。これが魅力の一つでしょう。
1> Person = #{name => spam}.
#{name => spam}
2> #{name := spam} = Person.
#{name => spam}
3> #{name := egg} = Person.
** exception error: no match of right hand side value #{name => spam}
このコードは name キーに spam というバリューをもった Person という Map を生成しています。 そしてその Person の中から name キーが spam であればパターンマッチ成功という実装です。
前述した new と put と update 以外にもいくつか関数があります。
get は key が見つからないとクラッシュします
1> Person = #{name => spam, age => 10}.
#{age => 10,name => spam}
2> maps:get(name, Person).
spam
3> maps:get(age, Person).
10
4> maps:get(gender, Person).
** exception error: bad_key
in function maps:get/2
called as maps:get(gender,#{age => 10,name => spam})
find は戻りが ok/error の形になり、見つからない場合は error を返します。
1> Person = #{name => spam, age => 10}.
#{age => 10,name => spam}
2> maps:find(name, Person).
{ok,spam}
3> maps:find(gender, Person).
error
keys は全てのキーがリストで取得できるようになりなります。
maps:keys/1:
1> Person = #{name => spam, age => 10}.
#{age => 10,name => spam}
2> maps:keys(Person).
[age,name]
Key が存在しているかを確認出来ます
maps:is_key/2:
3> maps:is_key(name, Person).
true
Map のサイズが取得できます
maps:size/1:
4> maps:size(Person).
2
値を順番に取得できます
maps:values/1:
5> maps:values(Person).
[10,spam]
指定した Key を削除します
maps:remove/2:
11> maps:remove(name, Person).
#{age => 10}
proplists から map に変換します
maps:from_list/1:
12> maps:from_list([{name, spam}, {age, 10}]).
#{age => 10,name => spam}
map から proplists に変換します
maps:to_list/1:
13> maps:to_list(#{age => 10,name => spam}).
[{age,10},{name,spam}]
皆さんがよく使っていた proplists:get_value/3 のデフォルトが指定出来るのはないのか、とお思いだと思いますが、merge を使う事で実現可能です。
maps:merge/2:
1> Person = #{name => spam, age => 10}.
#{age => 10,name => spam}
%% gender が空だった場合は male を指定するというコードです
2> maps:merge(#{gender => male}, Person).
#{age => 10,gender => male,name => spam}
%% gender が female で存在しているため gender の male は反映されていません
3> maps:merge(#{gender => male}, Person#{gender => female}).
#{age => 10,gender => female,name => spam}
erlang:is_map/1 と erlang:map_size/1 が追加されます。
前者は map 型かどうか、後者は maps:size/1 と同等です。
基本的には => と := の違いだけを学べば困ることはなさそうです。
また record で解決できていたところはできる限り record を使いましょう。
proplists で重複が許されなかったところ、設定ファイルなどが Map の出番だと思います。
- Big changes to Erlang
http://joearms.github.io/2014/02/01/big-changes-to-erlang.html
- Where are we on the Maps?
http://www.erlang-factory.com/upload/presentations/779/WhereareweontheMap.pdf
- Erlang R17 gets maps (August Lilleaas' blog)