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

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はElixirの教科書[『プログラミングElixir』](https://www.ohmsha.co.jp/book/9784274226373/)第8章を読んで、学んだことをまとめます。[^0]

#### 目次
[第4章へはこちらから](https://qiita.com/Alicesky2127/items/804c41110b0033fb7770)
[第5章へはこちらから](https://qiita.com/Alicesky2127/items/e12309be527d63644331)
[第6章へはこちらから](https://qiita.com/Alicesky2127/items/adccba8a61fe4ee2799b)
[第7章へはこちらから](https://qiita.com/Alicesky2127/items/584b2ac239c58e6c3613)
## 


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



以下私が詰まった箇所です。それ以外は本書か
[Elixir公式の学習ページ](https://elixir-lang.org/getting-started/basic-types.html#linked-lists)か、[Elixir School](https://elixirschool.com/ja/lessons/basics/basics)かで、学ぶことができます。




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



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


#### get/3 関数(keywords, key, default \\ nil)
```elixir
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)」で書いたもの](https://qiita.com/Alicesky2127/items/804c41110b0033fb7770)と比べてみてほしい。

#### drop/2 関数(map, keys)
```elixir
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)
```elixir
iex()> map2 = Map.put(map, :also_likes, "Ruby")
%{also_likes: "Ruby", likes: "Programming", name: "Dave", where: "Dallas"} 
#キーワードリストと違い順番が関係ない
```


## 8.4　マップのパターンマッチと更新
パターンマッチといえばマップ
```elixir
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　構造体
構造体とは、変数の型を自由に決められる箱。今回の目的としては、マップの型を示すためにマップを包むモジュール。


```elixir:defstruct.exs
#構造体の箱（モジュール）を作る
defmodule Subscriber do
  defstruct name: "", paid: false, over_18: true
end
```

```elixir
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)
入れ子の内側を呼び出すので、マップのキーはアトムで！（ドット記法で見やすく書こう！）

```elixir: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
```

```elixir
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の中身を変更してみる
```elixir
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)
```elixir
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"}]> #リストではないので順番は関係ない
```



<br>


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

https://qiita.com/piacerex/items/7bf8f9f4f5f576e597f5



[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^9]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。


まずは気軽に話しかけてみてください。[^10]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian

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

[^9]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。
[^10]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！