LoginSignup
14
1

More than 1 year has passed since last update.

未経験文系初学者 Elixirを学ぶ 『プログラミングElixir』-第8章

Last updated at Posted at 2022-05-06

こんにちは!
プログラミング未経験文系出身、Elixirの国に迷い込んだ?!見習いアルケミストのaliceと申します。
今回はElixirの教科書『プログラミングElixir』第8章を読んで、学んだことをまとめます。1

目次

第4章へはこちらから
第5章へはこちらから
第6章へはこちらから
第7章へはこちらから

実行環境

・Windows 11 Home(バージョン 21H2, OS ビルド 22000.613)
・Ubuntu v18.04 ※WSL2環境下
・Elixir v1.13.0 (compiled with Erlang/OTP 24) ※WSL2環境下
・Phoenix v1.6.7 ※WSL2環境下
・psql (PostgreSQL) 10.19 ※WSL2環境下

以下私が詰まった箇所です。それ以外は本書か
Elixir公式の学習ページか、Elixir Schoolかで、学ぶことができます。

8.1 マップとキーワードリスト、どちらを使うべきか

辞書型とは、キーと値がペアになったデータ構造。キーワードリストもマップもどちらも辞書型のデータ構造をしている。

8.2 キーワードリスト

キーがアトムであることが条件。キーが2単語以上に渡る場合はダブルクォーテーションで囲む。
(なお、値はどんな型でもよい)
関数に渡されるオプションの目的が多い。
要素の順番に意味がある。キーの重複が許されている。

get/3 関数(keywords, key, default \ nil)

iex()> Keyword.get([a: 1, b: 2, c: 3], :b)
2

iex()> Keyword.get([a: 1, b: 2, c: 3, b: 4], :b)
2 #キーが重複の場合、先にヒットした方が呼び出される

iex()> Keyword.get([a: 1, b: 2, c: 3], :d)
nil #デフォルト値が設定されていない場合でヒットなしの場合

iex()> Keyword.get([a: 1, b: 2, c: 3], :d, 0)
0 #デフォルト値が設定されている場合でヒットなしの場合

iex()> Keyword.get(["apple juice": 110, "banana juice": 220, coffee: 330], :"apple juice", 0)
110 #キーが2単語以上に渡る場合はダブルクォーテーションで囲む

8.3 マップ

要素の順番に意味はない。キーの重複が許されていない。

キーに型指定はない。が、アトムを使用すれば略記やドット記法が使える。
以下の例はキーと値のどちらもがアトムの場合の略記(key: value)を使用している。
第4章の「4.5 マップ(Map)」で書いたものと比べてみてほしい。

drop/2 関数(map, keys)

iex()> map = %{name: "Dave", likes: "Programming", where: "Dallas"} #略記する方が見やすい
%{likes: "Programming", name: "Dave", where: "Dallas"}

iex()> map1 = Map.drop(map, [:where, :likes]) 
%{name: "Dave"} 
#mapマップを直接いじっていない。map1という新しいマップに、mapにdrop/2関数を処理した結果を束縛している

put/3 関数(map, key, value)

iex()> map2 = Map.put(map, :also_likes, "Ruby")
%{also_likes: "Ruby", likes: "Programming", name: "Dave", where: "Dallas"} 
#キーワードリストと違い順番が関係ない

8.4 マップのパターンマッチと更新

パターンマッチといえばマップ

iex()> person = %{name: "Dave", height: 1.88}
%{height: 1.88, name: "Dave"}


#:name をキーとするエントリがあるか
iex()> %{name: a_name} = person #マップ内のname:キーに対応する値"Dave"とa_nameを束縛
%{height: 1.88, name: "Dave"} #エントリがある場合の返答


iex()> %{weight: a_weight} = person
** (MatchError) no match of right hand side value: %{height: 1.88, name: "Dave"}
#エントリがない場合の返答(値同士のパターンマッチができないことによるエラー)

iex()> a_name
"Dave"

#:name をキーとするエントリがあるか かつ :height をキーとするエントリもあるか
iex()> %{name: a_name ,height: a_height} = person #nameだけのパターンマッチに加えて、マップ内のheightのパターンマッチも行う
%{height: 1.88, name: "Dave"} #エントリがある場合の返答

8.5 マップの更新

特筆すべき箇所なし

8.6 構造体

構造体とは、変数の型を自由に決められる箱。今回の目的としては、マップの型を示すためにマップを包むモジュール。

defstruct.exs
#構造体の箱(モジュール)を作る
defmodule Subscriber do
  defstruct name: "", paid: false, over_18: true
end
iex()> s1 = %Subscriber{}
%Subscriber{name: "", over_18: true, paid: false} #構造体はマップの「%」と「{」の前にキャメルケースで名前を付ける

iex()> s2 = %Subscriber{name: "Mary", paid: true}
%Subscriber{name: "Mary", over_18: true, paid: true} #箱に値を入れる(デフォルト値と変わらないところは入れなくてよい)

iex()> s3 = %{s2 | name: "Marie"}
%Subscriber{name: "Marie", over_18: true, paid: true} #値の更新は新しいマップになる

8.7 入れ子になった辞書構造体

put_in/2 関数(path, value)

入れ子の内側を呼び出すので、マップのキーはアトムで!(ドット記法で見やすく書こう!)

defstruct2.exs
defmodule School do
  defstruct name: "", area: ""
end

defmodule Details do
  defstruct category: "", subject: ""
end


defmodule SchoolOrder do
  defstruct school: %School{}, details: %Details{}
end

上記を実行した上で、

$ iex defstruct2.exs
iex()> order = %SchoolOrder{school: %School{name: "NishiKokura", area: "Kita"}, details: %Details{category: "SummaryTes
ts", subject: "Math"}} # 入れ子になった辞書構造体の作成

%SchoolOrder{
  details: %Details{category: "SummaryTests", subject: "Math"},
  school: %School{area: "Kita", name: "NishiKokura"}
}

orderの中身を変更してみる

iex()> put_in(order.school.name, "MinamiKokura")
%SchoolOrder{
  details: %Details{category: "SummaryTests", subject: "Math"},
  school: %School{area: "Kita", name: "MinamiKokura"} #name: の値をNishiKokuraからMinamikokuraに変更

8.8 セット & 8.9 大いなる力には大いなる誘惑が伴う

MapSetモジュールには型を指定せずに値を複数放り込むことができる。

put/2 関数(map_set, value)

iex()> MapSet.new([1, :two, {"three"}]) #セット(集合)の作成
#MapSet<[1, :two, {"three"}]>

iex()> MapSet.put(MapSet.new([1, :two, {"three"}]), :four) #要素の追加
#MapSet<[1, :four, :two, {"three"}]> 

iex()> MapSet.put(MapSet.new([1, :two, {"three"}]), :two) #要素の追加(重複するので追加されないケース)
#MapSet<[1, :two, {"three"}]>

iex()> MapSet.put(MapSet.new([1, :two, {"three"}, :four]), 5.0)
#MapSet<[1, 5.0, :four, :two, {"three"}]> #リストではないので順番は関係ない

~Elixirの国のご案内~

※Elixirって何ぞや?と思ったらこちらもどぞ。未来がぎゅっと詰まった、Elixirは今年で生まれて10周年です:laughing::sparkles::sparkles:

We Are The Alchemists, my friends!:bouquet:2
Elixirコミュニティは本当に優しくて温かい人たちばかり!
私が挫折せずにいられるのもこの恵まれた環境のおかげです。

まずは気軽に話しかけてみてください。3

  1. プログラミングが完全未経験ゆえ、「え?!そこからつまずく?!!」というお見苦しい箇所があるかと思いますが、私自身の記録のために残します。ご了承ください。

  2. @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。

  3. @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中!

14
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
1