Elixirでは、コードの_Behaviour_を使って、共通の汎用的なインターフェースを提供しながら、それを実装するモジュールごとに固有の実装を行えるようにしています。そのようなよくある例のひとつが_Access Behaviour_です。
_Access Behaviour_は、キーを基にしたデータ構造からデータを取り出すための共通のインターフェースを提供します。_Access Behaviour_はマップとキーワードリストに対して実装されていますが、ここではマップでの使い方を見て、その雰囲気をつかんでみましょう。_Access Behaviour_では、マップがあるとき、そのあとに_角括弧_を続けてキーを書くと、そのキーに対応する値を取り出せると定められています。
# Suppose we have these two maps defined (note the difference in the key type)
my_map = %{key: "my value"}
your_map = %{"key" => "your value"}
# Obtain the value using the Access Behaviour
my_map[:key] == "my value"
your_map[:key] == nil
your_map["key"] == "your value"
データ構造の中にそのキーが存在しない場合、nilが返ります。これはエラーを発生させないため、意図しない動作の原因になることがあります。なお、nil自体もAccess Behaviourを実装しており、どんなキーに対しても常にnilを返します。
地元のバスケットボールチームのウェブサイトを保守するために、ウェブ開発チームと一緒に作業しています。ウェブ開発チームはElixirにあまり詳しくないため、迅速に開発を進められるよう、入れ子になったマップからデータを取り出す関数を求めています。
2つの引数を取るextract_from_path/2関数を実装しましょう。
data: バスケットボールチームに関するデータが入った入れ子のマップ構造。path: ピリオドで区切られたキーの文字列で、最後のキーに対応する値を取得するためのもの。パスの途中で値またはキーが存在しない場合は、nilを返します。
data = %{
"team_mascot" => %{
"animal" => "bear",
"actor" => %{
"first_name" => "Noel"
}
}
}
BasketballWebsite.extract_from_path(data, "team_mascot.animal")
# => "bear"
BasketballWebsite.extract_from_path(data, "team_mascot.colors")
# => nil
この関数を実装するときは、_Access Behaviour_を使います。
入れ子のマップデータ構造を扱うために、MapやKernelモジュールの関数を使わないでください。
コードをレビューしてくれている同僚が、実装とよく似たことをするKernelモジュールの関数を教えてくれます。
このKernelモジュールの関数を使うようにget_in_path/2を実装しましょう。
期待される引数は、パート1と同じです。
BasketballWebsite.get_in_path(data, "team_mascot.actor.first_name")
# => "Noel"