Scalaの基本を学ぶ

# はじめに

Scalaの基本を後から見直しやすいようにと思い要所要所まとめましたが、とても長い記事となっております。
逆引きのように見てもらえると幸いです。

## 動作環境

Scala：2.12

## 目次

- [Scalaとは](#scalaとは)
- [Scalaの基本](#scalaの基本)
- [制御構文](#制御構文)
    - [if式](#if式)
    - [While式](#while式)
    - [for式(`flatMap`・`map`・`withFilter`・`foreach`などあるが、ここでは基本的な使い方)](#for式flatmapmapwithfilterforeachなどあるがここでは基本的な使い方)
    - [match式](#match式)
- [クラス](#クラス)
    - [フィールド定義](#フィールド定義)
    - [抽象メンバー](#抽象メンバー)
    - [継承](#継承)
        - [継承する目的](#継承する目的)
- [オブジェクト](#オブジェクト)
- [トレイト](#トレイト)
    - [トレイトの基本](#トレイトの基本)
    - [菱形継承問題を解決するための線形化(linearization)](#菱形継承問題を解決するための線形化linearization)
    - [自分型](#自分型)
        - [落とし穴：トレイトの初期化順序](#落とし穴トレイトの初期化順序)
        - [トレイトの`val`の初期化順序の回避方法](#トレイトのvalの初期化順序の回避方法)
- [型パラメータと変位指定](#型パラメータと変位指定)
    - [共変(covariant)](#共変covariant)
- [関数](#関数)
    - [無名関数](#無名関数)
    - [関数のカリー化](#関数のカリー化)
- [コレクションライブラリ(immutable と mutable)](#コレクションライブラリimmutable-と-mutable)
    - [Array(mutable)](#arraymutable)
    - [Range](#range)
    - [List(immutable)](#listimmutable)
        - [Listの先頭に要素をくっつける](#listの先頭に要素をくっつける)
        - [List同士の連結](#list同士の連結)
        - [mkString：文字列のフォーマッティング](#mkstring文字列のフォーマッティング)
        - [foldLeft：左からの畳み込み](#foldleft左からの畳み込み)
        - [map：各要素を加工した新しい`List`を返す](#map各要素を加工した新しいlistを返す)
        - [filter：条件に合った要素だけを抽出した新しい`List`を返す](#filter条件に合った要素だけを抽出した新しいlistを返す)
        - [find：条件に合った最初の要素を返す](#find条件に合った最初の要素を返す)
        - [takeWhile：先頭から条件を満たしている間を抽出する](#takewhile先頭から条件を満たしている間を抽出する)
        - [count：`List`の中で条件を満たしている要素の数を計算する](#countlistの中で条件を満たしている要素の数を計算する)
        - [flatMap：`List`を平らにする](#flatmaplistを平らにする)
        - [Listの性能特性](#listの性能特性)
        - [紹介したメソッドについて](#紹介したメソッドについて)
    - [Vector(immutable)](#vectorimmutable)
    - [Map(immutable・mutable)](#mapimmutablemutable)
    - [Set(immutable・mutable)](#setimmutablemutable)
- [ケースクラスとパターンマッチング](#ケースクラスとパターンマッチング)
    - [部分関数](#部分関数)
- [エラー処理](#エラー処理)
    - [エラー処理で実現しなければならないこと](#エラー処理で実現しなければならないこと)
    - [例外の問題点](#例外の問題点)
    - [Option](#option)
    - [Optionのパターンマッチ](#optionのパターンマッチ)
    - [Optionの入れ子を解消する](#optionの入れ子を解消する)
    - [flatMap](#flatmap)
    - [Either](#either)
    - [Try](#try)
        - [`NonFatal`の例外](#nonfatalの例外)
    - [OptionとEitherとTryの使い分け](#optionとeitherとtryの使い分け)
- [Implicit](#implicit)
    - [Implicit Conversion(暗黙の型変換)](#implicit-conversion暗黙の型変換)
    - [Implicit Parameter(暗黙のパラメータ)](#implicit-parameter暗黙のパラメータ)

## Scalaとは

- オブジェクト指向プログラミングと関数型プログラミングの統合
- Javaと互換性があり、ライブラリも使用可能

## Scalaの基本

- 変数には、`val`と`var`の2種類がある
- `val`は値の再代入が不可。`var`は値の再代入が可能。基本的には`val`のみでプログラミングする
    - Swiftでいうところの、`let`(再代入不可)と`var`(再代入可能)

## 制御構文
### if式

```Scala
if (条件式) A {else B}
```

### while式

```Scala
while (条件式) A
```

### for式(`flatMap`・`map`・`withFilter`・`foreach`などあるが、ここでは基本的な使い方)

```Scala
for(ジェネレータ1; ジェネレータ2; ... ジェネレータn) A

# ジェネレータ1 = a1 <- exp1; ジェネレータ2 = a2 <- exp2; ... ジェネレータn = an <- expn
```

for式の例)

```Scala
for (x <- 1 to 5; y <- 1 until 5) {
    println("x = " + x + "y =" + y)
}
```
- `1 to 5`は1から5まで(5を含む)の範囲
- `1 until 5`は1から5まで(5を含まない)の範囲

`yield`を使ったfor式の例)

```Scala
for (e <- List("A", "B", "C", "D", "E")) yield {
    "Pre" + e
}
```
- `for`構文は`yield`キーワードを使うことで、コレクションの要素を加工して返すという全く異なる要素に使うことが可能

### match式

```Scala
マッチ対象の式 match {
    case パターン1 [if ガード1] => 式1
    case パターン2 [if ガード2] => 式2
    case パターン3 [if ガード3] => 式3
    case ...
    case パターンN [if ガードN] => 式N
}
```
- 漏れがないようにするために、パターンにワイルドカード(`_`など)を使用することも可能

## クラス
### フィールド定義

```Scala
(private[this/package名]/protected[package名]) (val/var) fieldName: Type = Expression
```
※ `private[this]`を付けたフィールドへのアクセスは一般にJVMレベルでのフィールドへの直接アクセスになるため、若干高速


### 抽象メンバー
その時点では実装を書くことができず、後述する継承の際に、メソッド・フィールドの実装を与えたいという時に、抽象メンバーを定義する。

抽象メンバーのメソッド実装例)

```Scala
(private[this/package名]/protected[package名]) def methodName(parameter1: Type1, parameter2: Type2, ...): ReturnType
```
抽象メンバーのフィールド実装例)

```Scala
(private[this/package名]/protected[package名]) (val/var) fieldName: Type
```


### 継承
#### 継承する目的

1. スーパークラスの実装をサブクラスでも使うことで実装を再利用すること
2. 複数のサブクラスが共通のスーパークラスのインターフェースを継承することで処理を共通化すること(サブタイピング・ポリモーフィズムと呼ぶ)

- Scalaでは、トレイトという仕組みで複数の実装の継承を実現している。(下記の[トレイト](#トレイト)を参照)

クラスの継承)

```Scala
class SubClass(....) extends SuperClass {
    ....
}
```

## オブジェクト

- Scalaでは、全ての値がオブジェクトで、全てのメソッドは何らかのオブジェクトに所属している

`object`構文の主な用途

1. ユーティリティメソッドやグローバルな状態の置き場所
2. オブジェクトのファクトリメソッド
3. Singletonパターン

`object`の基本構文)

```Scala
object オブジェクト名 extends クラス名 with トレイト名2 ... {
    本体
} 
```

- クラスと同じファイル内、同じ名前で定義されたシングルトンオブジェクトは、コンパニオンオブジェクトと呼ばれる
    - コンパニオンオブジェクトは、対応するクラスに対して特権的なアクセス権を持つ


## トレイト

- Scalaのトレイトはクラスからコンストラクタを定義する機能を抜いたようなもの

トレイトの定義)

```Scala
trait TraitName {
    (a filed or a method definition)の0回以上の繰り返し
}
```

### トレイトの基本

クラスに比べて以下のような特徴がある

- 複数のトレイトを1つのクラスやトレイトにミックスインできる
    - 複数のクラスを継承させたい場合は、クラスをトレイトにする必要がある
- 直接インスタンス化できない
    - トレントを使うときは通常、それを継承したクラスを作る。これは、トレントが単体で使われることを想定していないための制限である。
- クラスパラメータ(コンストラクタの引数)を取ることができない
    - トレイトに抽象メンバを持たせることで値を渡すことが可能

```Scala
trait TraitA {
    val name: String
    def printName(): Unit = println(name)
}

// クラスにしてnameを上書きする
class ClassA(val name: String) extends TraitA

object ObjectA {
    val a = new ClassA("Objective-C")

    // nameを上書きするような実装を与えてもよい
    val a2 = new TraitA { val name = "Swift" }
}
```

### 菱形継承問題を解決するための線形化(linearization)

継承関係が複雑になったメソッドを全て明示的に呼ぶのは大変であるため、
トレイトがミックスインされた順番をトレイトの継承順番とみなす線形化という機能がある。

```Scala
trait TraitA {
    def greet(): Unit
}

trait TraitB extends TraitA {
    override def greet(): Unit = println("Good morning!")
}

trait TraitC extends TraintA {
    override def greet(): Unit = println("Good evening!")
}

class ClassA extends TraitB with TraitC
```

実行文)

```scala
scala> (new ClassA).greet()

Good everning!
```
トレイトの継承順番が線形化され、後からミックスインした`TraitC`が優先されているため、`ClassA`の`greet`メソッドの呼び出しで`TraitC`の`greet`メソッドが実行されている。

### 自分型

- 自分型を使う場合、抽象トレイトを指定し、後から実装を追加するという形になる
    - このように後(または外)から利用するモジュールの実装を与えることを「依存性の注入」と呼ぶ
- 型の循環参照(相互参照)を許す

#### 落とし穴：トレイトの初期化順序

```Scala
trait A {
    val foo: String
}

trait B extends A {
    val bar = foo + "World"
}

class C extends B {
    val foo = "Hello"

    def printBar(): Unit = println(bar)
}
```

実行文)

```Scala
scala> (new C).printBar()

nullWorld
```
Scalaのクラス・トレントはスーバークラスから順番に初期化される。
そのため、この例では、クラス`C`はトレイト`B`を継承し、トレイト`B`はトレイト`A`を継承している。
つまり、初期化はトレイト`A`が一番先に行われ変数`bar`が宣言され、中身は何も代入していないので、nullになる。次に、トレント`B`で変数`bar`が宣言され、`null`である`foo`と"World"という文字列から`"nullWorld"`という文字列が作られ、変数`bar`に代入される。

#### トレイトの`val`の初期化順序の回避方法

```scala

trait A {
    val foo: String
}

trait B extends A {
    lazy val bar = foo + "World" //もしくは def bar でもよい
}

class C extends B {
    val foo = "Hello"

    def printBar(): Unit = println(bar)
}
```

実行文

```scala
cala
scala> (new C).printBar()

HelloWorld
```

`bar`の初期化に`lazy val`を使うことで、`bar`の初期化が実際に行われるまで遅延されることがなくなる。

## 型パラメータと変位指定

Scalaでは、何も指定しなかった型パラメータは通常は非変(invariant)になる。

### 共変(covariant)

配列型はJavaでは共変

```Java:covariant.java
Object[] objects = new String[1];
objects[0] = 100;
```
このJavaのコードはコンパイルは通るが、
実行すると、`java.lang.ArrayStoreException`が発生する。
これは、`objects`に入っているのが、実際には、`String`の配列(`String`のみを要素として持つ)なのに、2行目で`int`型(ボクシング変換されて`Integer型`)の値である`100`を渡そうとしていることになる。

配列型はScalaでは非変なので、上記のコードをコンパイルするとその時点でエラーが表示される。

## 関数

Scalaの関数は、単に`Function0` 〜 `Function22`までのトレントの無名サブクラスのインスタンスである。

２つの関数を取って加算した値を返す`add`関数の定義例)

```scala
val add = new Function2[Int, Int, Int] {
    def apply(x: Int, y: Int): Int = x + y
}
```

### 無名関数

先ほどのように関数定義するとコードが冗長になり過ぎる。
そのため、Scalaでは、`Function0` 〜 `Function22`までのトレントのインスタンスを生成するためのシンタックスシュガーが用意されている。

シンタックスシュガーを使って`add`関数を定義した例)

```Scala
val add = (x: Int, y: Int) => x + y
```
実行例)

```Scala
scala> add(100, 200)

res1: Int = 300
```

### 関数のカリー化

カリー化とは、`(Int, Int) => Int`型の関数のように複数の引数を取る関数があったとき、
これを`Int => Int => Int`型の関数のように1つの引数を取り、残りの引数を取る関数を返す関数のチェインで表現するというもの。

上記の`add`をカリー化した`addCurried`関数を定義した例

```Scala
val addCurried = (x: Int) => ((y: Int) => x + y)
```

実行例)

```Scala
scala> addCurried(100)(200)

res1: Int = 300
```

## コレクションライブラリ(immutable と mutable)

Scalaには、一度作成したら変更できない(immutable)なコレクションと変更できる(mutable)通常のコレクションがある。

immutableなコレクションを使うメリット

1. 関数型プログラミングで多用する再起との相性が良い
2. 高階関数を用いて簡潔なプログラムを書くことができる
3. 一度作ったコレクションが知らない箇所で
4. 並行に動作するプログラムの中で、安全に受け渡しすることができる

### Array(mutable)

Arrayの定義例)

```Scala
val arr = Array(1, 2, 3, 4, 5)
// 型を省略せずに書くと
val arr = Array[Int](1, 2, 3, 4, 5)
```
ここで、`[Int]`の部分は型パラメータと呼ぶ。
`Array`だけではどの型か分からないので、`[Int]`と付けることでどの型の`Array`かを指定している。(しかし、この場面では、`Array`の要素型は`Int`だとわかっているので、冗長な書き方)
この型パラメータは型推論を補うために、色々な箇所で出てくる。

### Range

`Range`は範囲を表すオブジェクト

`Range`の使用例)

```Scala
scala> 1 to 5
res1: scala.collection.immutable.Range.Inclusive = Range 1 to 5

scala> (1 to 5).toList
res2: List[Int] = List(1, 2, 3, 4, 5)

scala> 1 until 5
res3: scala.collection.immutable.Range = Range 1 until 5

scala> (1 until 5).toList
res4: List[Int] = List(1, 2, 3, 4)
```

### List(immutable)

Scalaでは`Array`を使うことはそれほど多くなく、`List`や`Vector`といったデータ構造を多用する。
`List`の特徴は、一度作成したら中身を変更できない(immutable)であること。
中身を変更できないデータ構造(永続データ構造と呼ぶ)はScalaがサポートしている関数型プログラミングにとって重要な要素。

`List`の実行例)

```Scala
scala> val lst = List(1, 2, 3, 4, 5)
lst: List[Int] = List(1, 2, 3, 4, 5)

scala> lst(0) = 7
<console>:13: error: value update is not a member of List[Int]
       lst(0) = 7
       ^
```
`List`は値を更新することはできないが、その代わりとして`List`を元に新たな`List`を作ることができる。

#### Listの先頭に要素をくっつける

`::`(コンスと読む)は既にある`List`の先頭に要素をくっつけるメソッド

実行例)

```Scala
scala> val a1 = 1 :: Nil
a1: List[Int] = List(1)

scala> val a2 = 2 :: a1
a2: List[Int] = List(2, 1)
```

#### List同士の連結

`++`はList同士を連結するメソッド

実行例)

```Scala
scala> List(1, 2) ++ List(3, 4)
res1: List[Int] = List(1, 2, 3, 4)
```
※ 大きな`List`同士を連結する場合、計算量が大きくなるので注意

#### mkString：文字列のフォーマッティング

mkStringフォーマッティングのやり方は3種類ある。

- mkString(引数なしバージョン)

```Scala
scala> List(1, 2, 3, 4, 5).mkString
res1: String = 12345
```

※ 引数なしメソッドの`mkString`は`()`を付けて読みだすことが**できない**。
  逆に`()`を使って定義されたメソッドは、`()` を付けても付けなくても良いことになっているので注意

- mkString(sep: String)

```Scala
scala> List(1, 2, 3, 4, 5).mkString(",")
res1: String = 1,2,3,4,5
```

- mkString(start: String, sep: String, end: String)

```Scala
scala> List(1, 2, 3, 4, 5).mkString("[", ",", "]")
res1: String = [1,2,3,4,5]
```

#### foldLeft：左からの畳み込み

foldLeftメソッドの宣言)

```Scala
def foldLeft[B](z: B)(f: (B, A) => B): B
```

実行例)

```Scala
// Listの要素の合計を求める場合の例
scala> List(1, 2, 3).foldLeft(0)((x, y) => x + y)
res0: Int = 6

// Listの要素を全て掛け合わせた結果を求める場合の例
scala> List(2, 2, 3).foldLeft(1)((x, y) => x * y)
res1: Int = 12
```

与える引数の順序がちょうど対称となっている`foldRight`メソッドも存在する。

#### map：各要素を加工した新しい`List`を返す

`map`メソッドは、1引数の関数を引数に取り、各要素に関数を適用した結果で生まれた要素からなる新たな`List`を返す

Listの各要素を2倍した`map`メソッドの実行例)

```Scala
scala> List(1, 2, 3, 4, 5).map(x => x * 2)
res0: List[Int] = List(2, 4, 6, 8, 10)
```

`x => x * 2`の部分は、無名関数を定義するための構文。

#### filter：条件に合った要素だけを抽出した新しい`List`を返す

`filter`メソッドは`Boolean`型を返す1引数の関数を引数に取り、各要素に関数を適用し、`true`になった要素のみを抽出した新たな`List`を返す

List内の奇数だけ抽出する実行例)

```Scala
scala> List(1, 2, 3, 4, 5).filter(x => x % 2 == 1)
res0: List[Int] = List(1, 3, 5)
```

#### find：条件に合った最初の要素を返す

`find`メソッドは`Boolean`型を返す1引数の関数を引数に取り、各要素に前から順番に関数を適用し、最初に`true`になった要素を`Some`でくるみ、`Option`型をして返す。1つの要素もマッチしなかった場合は、`None`を`Option`型として返す。

List内の最初の奇数だけを抽出する実行例)

```Scala
scala> List(1, 2, 3, 4, 5).find(x => x % 2 == 1)
res0: Option[Int] = Some(1)
```


#### takeWhile：先頭から条件を満たしている間を抽出する

`takeWhile`メソッドは、`Boolean`型を返す1引数の関数を引数に取り、前から順番に関数を適用し、結果が`true`の間のみからなる`List`を返す

List内の5より前の4要素を抽出する実行例)

```Scala
scala> List(1 ,2 ,3, 4, 5).takeWhile(x => x != 5)
res0: List[Int] = List(1, 2, 3, 4)
```

#### count：`List`の中で条件を満たしている要素の数を計算する

`count`メソッドは、`Boolean`型を返す1引数の関数を引数に取り、全ての要素に関数を適用し、`true`が返ってきた要素の数を計算する。

List内の偶数の数を計算する例)

```Scala
scala> List(1, 2, 3, 4, 5).count(x => x % 2 == 0)
res0: Int = 2
```

#### flatMap：`List`を平らにする

`flatMap`メソッドの宣言)

```Scala
final def flatMap[B](f: (A) => GenTraversableOnce[B]): List[B]
```

`GenTraversableOnce[B]`はあらゆるコレクション(要素の型はB型である)を入れることができる型と考える。

`flatMap`の使用例1)

```Scala
scala> List(List(1, 2, 3), List(4, 5)).flatMap{e => e.map{g => g + 1}}
res0: List[Int] = List(2, 3, 4, 5, 6)
```

使用例1は、ネストした`List`の各要素に`flatMap`の中で`map`を適用し、`List`の各要素に1を足したものを平らにしている。

`flatMap`の使用例2)

```Scala
scala> List(1, 2, 3).flatMap{e => List(4, 5).map(g => e * g)}
res0: List[Int] = List(4, 5, 8, 10, 12, 15)
```

使用例2は、`List(1, 2, 3)`と`List(4, 5)`の2つの`List`についてループし、各々の要素を掛け合わせた要素からなる`List`を抽出している

#### Listの性能特性

- `List`の先頭要素へのアクセスは高速にできる
- 要素へのランダムアクセスや末尾へのデータ追加は、`List`の長さに比例した時間がかかってしまう

#### 紹介したメソッドについて

`mkString`をはじめとした`flatMap`など`List`の色々なメソッドを紹介してきたが、これらの大半は、`List`特有ではなく、
`Range`や`Array`などの他のコレクションでも同様に使うことができる。
その理由は、これらのメソッドによる操作の大半は、コレクションのスーパークラスである共通トレイト中に宣言されているからである。
各メソッドの詳細は[ScalaのAPIドキュメント](https://www.scala-lang.org/api/current/index.html)より。

他のコレクションライブラリについては、以下の公式ドキュメントを参照

- [Scala Collections](https://docs.scala-lang.org/ja/overviews/collections/introduction.html)

### Vector(immutable)

`Vector`は一度データ構造を構築したら変更できないimmutableなデータ構造である。
要素へのランダムアクセス・長さの取得・データの挿入や削除などいずれの操作も十分高速にできる。

`Vector`の使用例)

```Scala
scala> Vector(1, 2, 3, 4, 5)
res0: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4, 5)

scala> Vector(1, 2, 3, 4, 5) :+ 6
res1: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4, 5, 6)

scala> Vector(1, 2, 3, 4, 5).updated(2, 8)
res2: scala.collection.immutable.Vector[Int] = Vector(1, 2, 8, 4, 5)
```

### Map(immutable・mutable)

`Map`はキーから値へのマッピングを提供するデータ構造。(他の言語では、辞書や連想配列と呼ばれたりする)
Scalaでは、一度作成したら変更できないimmutableな`Map`と変更できるmutableな`Map`の2種類が提供されている。

Scalaでは、何も設定せず`Map`と書いた場合、`scala.collection.immutable.map`が使われる。

`scala.collection.immutable.map`の使用例)

```Scala
scala> val m = Map("A" -> 1, "B" -> 2, "C" -> 3)
m: scala.collection.immutable.Map[String,Int] = Map(A -> 1, B -> 2, C -> 3)

scala> m.updated("A", 0) //一見元のMapが変更されたように見えるが
res1: scala.collection.immutable.Map[String,Int] = Map(A -> 0, B -> 2, C -> 3)

scala> m // 元のMapはそのままで変更されていない
res2: scala.collection.immutable.Map[String,Int] = Map(A -> 1, B -> 2, C -> 3)
```

`scala.collection.mutable.map`の使用例)

```Scala
scala> import scala.collection.mutable
import scala.collection.mutable

scala> val m = mutable.Map("A" -> 1, "B" -> 2, "C" -> 3)
m: scala.collection.mutable.Map[String,Int] = Map(A -> 1, C -> 3, B -> 2)

scala> m("A") = 0 // A -> 0のマッピングに置き換える

scala> m // 変更が反映されている
res0: scala.collection.mutable.Map[String,Int] = Map(A -> 0, C -> 3, B -> 2)
```

### Set(immutable・mutable)

`Set`は値の集合を提供するデータ構造。
`Set`の中では同じ値が2以上存在しない。(重複した値は自動で削除される)

`Map`と同じでScalaでは何も設定せず`Set`と書くと、`scala.colletion.immutable.Set`が使われる

`scala.colletion.immutable.Set`の使用例)

```Scala
scala> val s = Set(1, 1, 3, 4, 5)
s: scala.collection.immutable.Set[Int] = Set(1, 3, 4, 5)

scala> s - 5 // 5を削除した後も
res0: scala.collection.immutable.Set[Int] = Set(1, 3, 4)

scala> s // 元のSetはそのまま
res1: scala.collection.immutable.Set[Int] = Set(1, 3, 4, 5)
```

`scala.colletion.mutable.Set`の使用例)

```Scala
scala> import scala.collection.mutable
import scala.collection.mutable

scala> val s = mutable.Set(1, 1, 3, 4, 5)
s: scala.collection.mutable.Set[Int] = Set(1, 5, 3, 4)

scala> s -= 5 // 5を削除したら
res0: s.type = Set(1, 3, 4)

scala> s // 変更が反映される
res1: scala.collection.mutable.Set[Int] = Set(1, 3, 4)
```

## ケースクラスとパターンマッチング

簡単なケースクラスによるデータ型の定義

```Scala
sealed abstract class DayOfWeek
case object Sunday extends DayOfWeek
case object Monday extends DayOfWeek
case object Tuesday extends DayOfWeek
case object Wednesday extends DayOfWeek
case object Thursday extends DayOfWeek
case object Friday extends DayOfWeek
case object Saturday extends DayOfWeek
```

CやJavaとの列挙型との違いは、

- 各々のデータは独立してパラメータを持つことができること

パターンマッチングを用いて定義することで、

1. ノードの種類と構造によって分岐する
2. ネストしたノードを分解する
3. ネストしたノードを分解した結果を変数に束縛する

という3つの動作が同時に行える。

ある日の次の曜日を返すメソッド`nextDayOfWeek`をパターンマッチを用いて定義している例)

```Scala
def nextDayOfWeek(d: DayOfWeek): DayOfWeek = d match {
    case Sunday => Monday
    case Monday => Tuesday
    case Tuesday => Wednesday
    case Wednesday => Thursday
    case Thursday => Friday
    case Friday => Saturday
    case Saturday => Sunday
}
```

実行例)

```Scala
scala> nextDayOfWeek(Sunday)
res0: DayOfWeek = Monday
```

※ 変数宣言でもパターンマッチングを行うことが可能

変数宣言でパターンマッチングを行なっている例)

```Scala
scala> case class Point(x: Int, y: Int)
defined class Point

scala> val Point(x, y) = Point(10, 20)
x: Int = 10
y: Int = 20
```

### 部分関数

無名関数とパターンマッチングの2つの機能を組み合わせた、部分関数(PartialFunction)がScalaには存在する

無名関数の具体的なユースケース)

```Scala
scala> List(1, 2, 3, 4 ,5).collect { case i if i % 2 == 1 => i * 2 }
res0: List[Int] = List(2, 6, 10)
```

ここで、`collect`メソッドは、`pf: PartialFunction[A, B]`を引数に取り、`pf.isDefinedAt(i)`が`true`になる要素のみを残し、さらに、`pf.apply(i)`の結果の値を元にした新しいコレクションを返します。

`isDefinedAt`は、

```
i % 2 == 1
```
の部分から自動的に生成され、パターンがマッチするときのみ真(`true`)になるように定義される。


## エラー処理

Scalaでのエラー処理は

1. 例外を使う方法
2. OptionやEitherやTryなどのデータ型を使う方法

の2つの方法があり、状況に応じて使い分けることになる。

### エラー処理で実現しなければならないこと

- 例外安全性
    - 例外が発生してもシステムがダウンしたり、データの不整合などの問題が起きないようにする概念のこと
- 強い例外安全性
    - 例外が発生した場合、全ての状態が例外発生前に戻らなければならないという概念のこと

### 例外の問題点

Javaのエラー処理は例外が中心的な役割を担っていて、Scalaでも例外は多く使われる。しかし、例外は便利な反面、以下のような問題もある。

- 例外と使うとコントロールフローがわかりづらくなる
    - 適切に使えば正常系の処理とエラー処理を分離し、コードの可読性を上げ、エラー処理をまとめる効果があるが、例外のcatch漏れや、例外をcatchしているところで、どこで発生した例外をcatchしているのか判別できないため、コードの修正を阻害する場合もある
- 例外は非同期プログラミングでは使えない
    - 例外の動作は送出されたらcatchされるまで、コールスタックを遡っていくというもの。そのため、別スレッド・別のイベントループなどで実行される非同期プログラミングでは相容れない
- 例外は型チェックできない
    - チェック例外を使わない場合、メソッドの型として表現されない。(Scalaでは、高階関数でチェック例外を扱うことが難しいという問題が大きく、チェック例外の機能は無くなっている)また、間違った例外をキャッチしているかは、実行時にしか分からない。

### Option

OptionはScalaで多用されるデータ型の1つ。
Option型には、以下の2つの値が存在する。

- `Some`
- `None`

`Option`に具体的な値が入っている場合の実行例)

```Scala
scala> val o: Option[String] = Option("hoge")
o: Option[String] = Some(hoge)

scala> o.get
res0: String = hoge

scala> o.isEmpty
res1: Boolean = false

scala> o.isDefined
res2: Boolean = true
```

`Option`に`null`が入っている場合の実行例)

```Scala
scala> val o: Option[String] = Option(null)
o: Option[String] = None

scala> o.isEmpty
res0: Boolean = true

scala> o.isDefined
res1: Boolean = false
```

### Optionのパターンマッチ

Optionは型を持っているため、パターンマッチを使って処理することもできる。

実行例)

```Scala
scala> val s: Option[String] = Some("hoge")
s: Option[String] = Some(hoge)

scala> val result = s match {
     | case Some(str) => str
     | case None => "not matched"
     | }
result: String = hoge
```

上記のようにSomeかNoneにパターンマッチすることで、Someにパターンマッチする場合には、その中身の値を`str`という別の変数に束縛することが可能。

### Optionの入れ子を解消する

キャッシュから情報を取得する場合、キャッシュヒットする場合と、キャッシュミスする場合があり、それらは、ScalaではOption型で表現されることが多い。
以下のようなキャッシュ取得が連続で繰り返された場合、Optionが入れ子になってしまう。

1つ目と2つ目の整数の値がOptionで返ってきて、それをかけた値を求める実行例)

```Scala
scala> val v1: Option[Int] = Some(3)
v1: Option[Int] = Some(3)

scala> val v2: Option[Int] = Some(5)
v2: Option[Int] = Some(5)

scala> v1.map(i1 => v2.map(i2 => i1 * i2))
res0: Option[Option[Int]] = Some(Some(15))
```

Optionの入れ子を解消するためには、`flatten`を実行すれば良い。

`flatten`を実行し、Optionの入れ子を解消している例)

```Scala
scala> val v1: Option[Int] = Some(3)
v1: Option[Int] = Some(3)

scala> val v2: Option[Int] = None
v2: Option[Int] = None

scala> v1.map(i1 => v2.map(i2 => i1 * i2)).flatten
res0: Option[Int] = None
```
上記のように、v2がNoneである場合でも、`flatten`は成立する。そのため、キャッシュミスでSomeの値が取れなかった際も問題なく処理が動く。

### flatMap

`map`と`flatten`は、実際はこの両方を組み合わせて使うことが多い。
`flatMap`は、Optionに`map`をかけて`flatten`を適用してくれるメソッド

```Scala
scala> val v1:  Option[Int] = Some(3)
v1: Option[Int] = Some(3)

scala> val v2:  Option[Int] = Some(5)
v2: Option[Int] = Some(5)

scala> val v3:  Option[Int] = Some(7)
v3: Option[Int] = Some(7)

scala> v1.flatMap(i1 => v2.flatMap(i2 => v3.map(i3 => i1 * i2 * i3)))
res0: Option[Int] = Some(105)
```

### Either

Eitherは、エラー時にエラーの種類まで取得できる。
Optionでは、Noneが返ってきた場合、値が取得できなかったことはわかるがエラーの状態は取得できないので、エラーの種類がわからなくても問題にならない場合のみ使える。
具体的には、Optionは`Some`と`None`の2つの値を持つが、Eitherは`Right`と`Left`の２つの値を持つ。

### Try

TryはEitherと同じように正常な値とエラー値のどちらかを表現するデータ型。
Eitherとの違いは、2つの型が平等ではなく、エラー値がThrowableに限定されており、型引数を1つしか取らないこと。
具体的には、Tryは`Success`と`Failure`の2つの値を持つ。

`Success`は型変数を取り任意の値を入れることができるが、`Failure`はThrowableしか入れることができない。
そして、Tryには、コンパニオンオブジェクトのapplyで生成する際に、例外をcatchしFailureにする機能がある。

Tryの実行例)

```Scala
scala> import scala.util.Try
import scala.util.Try

scala> val v: Try[Int] = Try(throw new RuntimeException("to be caught"))
v: scala.util.Try[Int] = Failure(java.lang.RuntimeException: to be caught)
```

この機能を使って、例外が起こりそうな箇所を`Try`で包み、`Failure`にして値として扱えるようにするのがTryの特徴

```Scala
scala> val v1 = Try(3)
v1: scala.util.Try[Int] = Success(3)

scala> val v2 = Try(5)
v2: scala.util.Try[Int] = Success(5)

scala> val v3 = Try(7)
v3: scala.util.Try[Int] = Success(7)

scala> for {
     | i1 <- v1
     | i2 <- v2
     | i3 <- v3
     | } yield i1 * i2 * i3
res0: scala.util.Try[Int] = Success(105)
```

#### `NonFatal`の例外

`Try.apply`がcatchするのは全ての例外ではなく、NonFatalという種類の例外のみ。
その理由は、NonFatalでないエラーはアプリケーション中で復旧が困難で重度なものであるから。

Try以外でも、扱うことができる全ての例外をまとめて処理する場合などに以下のようなコードが出てくることがある。

```Scala
import scala.util.control.NonFatal

try {
    ???
} catch {
    case NonFatal(e) => // 例外の処理
}

```

### OptionとEitherとTryの使い分け

- Optionは、Javaでnullを使うような場面で使うのが良い。
- Eitherは、Optionを使うのでは情報が不足しており、エラー状態が代数的データ型として定められるものに使うのが良い。Javaでチェック例外を使っていたような復帰可能なエラーだけに使うという考え方でも良い。
- Tryは、Javaの例外をどうしても値として扱いたい場合に使うのが良い。非同期プログラミングや、実行結果を保存し中身を参照する場合などに使うことも考えられる。

## Implicit

### Implicit Conversion(暗黙の型変換)

implicit conversionは暗黙の型変換機能をユーザーが定義できるようにする機能。

implicit conversionの定義例)

```Scala
implicit def メソッド名(引数名: 引数の型): 返り値の型 = 本体
```

implicit conversionは大きく分けて二通りの使われ方をする

1. 新しく定義したユーザー定義の型などを既存の型に当てはめたい場合
2. pimp my libraryパターンと呼ばれる、既存のクラスにメソッドを追加し拡張する(ようにみせかける)使い方

1つ目の実行例)

```Scala
scala> implicit def intToBoolean(arg: Int): Boolean = arg != 0
intToBoolean: (arg: Int)Boolean

scala> if(1) {
     | println("1はTrueである")
     | }
1はTrueである
```
といった形で、本来`Boolean`しか渡せないはずにif式に`Int`を渡すことができる。
※ implicit conversion を定義することで、コンパイラで本来はif文の条件式には`Boolean`型の式しか渡せないようチェックしているものを通り抜けてしまうため、本当にその変換が必要であるかよく考える必要がある

2つ目の実行例1)

```Scala
scala> class RichString(val src: String) {
     | def smile: String = src + "(^ ^)"
     | }
defined class RichString

scala> implicit def enrichString(arg: String): RichString = new RichString(arg)
enrichString: (arg: String)RichString

scala> "Hi! ".smile
res0: String = Hi! (^ ^)
```

コンパイラは、ある型に対するメソッド呼び出しを見つけたとき、そのメソッドを定義した型がimplicit conversionの返り値の型にないか検索し、型が合ったらimplicit conversionの呼び出しを挿入する。
2つ目の実行例1 では、`String`の末尾に`"(^ ^)"`という文字列を追加して返すimplicit conversionを定義している。

2つ目の実行例1は、Scala 2.10以降では、以下のように書き直すことが可能

2つ目の実行例2)

```Scala
scala> implicit class RichString(val src: String) {
     | def smile: String = src + "(^ ^)"
     | }
defined class RichString

scala> "Hi! ".smile
res0: String = Hi! (^ ^)
```

### Implicit Parameter(暗黙のパラメータ)

implicit Parameterは大きく分けて二通りの使われ方をする

1. メソッドで共通に引き渡されるオブジェクト(ソケットやDBのコネクションなど)を明示的に引き渡すのを省略するために使う
2. 型クラスを定義・使用することを可能にするために使う

1つ目の使い方の具体例)
以下のようなDBとのコネクションを表す`Connection`型があるとする。DBと接続するメソッドは、全てこの`Connection`型を引き渡さなければならない。

```Scala
def useDatabase1(..../ conn: Connection)
def useDatabase2(..../ conn: Connection)
def useDatabase3(..../ conn: Connection)
```

この3つのメソッドは共通して`Connection`型を引数に取るにも関わらず、呼び出す度に明示的に`Connection`オブジェクトを渡さなければならず面倒である。
上のメソッド定義をimplicit parameterを使い以下のように書き換える。

```Scala
def useDatabsse1(....)(implicit conn: Connection)
def useDatabsse2(....)(implicit conn: Connection)
def useDatabsse3(....)(implicit conn: Connection)
```
Scalaのコンパイラは、このように定義されたメソッドが呼び出されると、現在のスコープからたどって直近のimplicitとマークされた値を暗黙でメソッドに引き渡す。

値をimplicitとしてマークする例)

```Scala
implicit val connection: Connection = connectDatabase(....)
```

このようなimplicit parameterの使い方は、Play 2 FrameworkやScalaの各種O/Rマッパーで頻出する。

2つめの使い方の具体例として、`List`の全ての要素の値を加算した結果を返す`sum`メソッドを定義したいとする。
この際、「何の」`List`か全く分かっていない場合、整数の`+`メソッドをそのまま使うことはできない。
この問題を解決するために、2つの手順を踏む。
まず、2つの同じ型を足す(0の場合はそれに相当する値を返す)方法を知っている型を定義する。
ここでは、その型を`Addtive`とする。

`Additive`の定義)

```Scala
trait Additive[A] {
    def plus(a: A, b: A): A
    def zero: A
}
```

ここで、`Additive`の型パラメータ`A`は加算される`List`の要素の型を表している。また、

- `zero`：型パラメータAの**0**に相当する値を返す
- `plus`：型パラメータAを持つ2つの値を**加算して**返す

となっている。

次に、この`Additive`型を使って、`List`の全ての要素を合計するメソッドを定義する

```Scala
def sum[A](lst: List[A])(m: Additive[A]) = lst.foldLeft(m.zero)((x, y) => m.plus(x, y))
```

後は、それぞれの型に応じた加算と0の定義を持ったobjectを定義する。
ここでは、`String`と`Int`について定義する。

```Scala
object StringAdditive extends Additive[String] {
    def plus(a: String, b: String): String = a + b
    def zero: String = ""
}

object IntAdditive extends Additive[Int] {
    def plus(a: Int, b: Int): Int = a + b
    def zero: Int = 0
}
```

これで、`Int型`の`List`も`String`型の`List`のどちらの要素の合計も計算できる汎用的な`sum`メソッドができた。
まとめると、以下のようになる。

`Int型`の`List`も`String`型の`List`のどちらの要素の合計も計算できる`sum`メソッドの実装例)

```Scala
trait Additive[A] {
    def plus(a: A, b: A): A
    def zero: A
}

object StringAdditive extends Additive[String] {
    def plus(a: String, b: String): String = a + b
    def zero: String = ""
}

object IntAdditive extends Additive[Int] {
    def plus(a: Int, b: Int): Int = a + b
    def zero: Int = 0
}

def sum[A](lst: List[A])(m: Additive[A]) = lst.foldLeft(m.zero)((x, y) => m.plus(x, y))
```

`sum`メソッドの実行例)

```Scala
scala> sum(List(1, 2, 3))(IntAdditive)
res0: Int = 6

scala> sum(List("S", "w", "i", "f", "t"))(StringAdditive)
res1: String = Swift
```

これで、目的は果たすことができたが、`sum`メソッドを使えば何の`List`の要素を合計するかは型チェックで分かっているのだから、引数に`IntAdditive`,`StringAdditive`を明示的に渡すことなく、推論してほしい。
前置きが長くなってしまったが、これをimplicit parameterで実現することができる。

方法は、

- `IntAdditive`,`StringAdditive`の定義の前にimplicitと付ける
- `sum`の最後の引数リストの`m`にimplicitを付ける

だけである。

implicit parameterを使い、`IntAdditive`,`StringAdditive`を明示的に渡すことなく推論可能にした形は以下の通りである。

```Scala
trait Additive[A] {
    def plus(a: A, b: A): A
    def zero: A
}

implicit object StringAdditive extends Additive[String] {
    def plus(a: String, b: String): String = a + b
    def zero: String = ""
}

implicit object IntAdditive extends Additive[Int] {
    def plus(a: Int, b: Int): Int = a + b
    def zero: Int = 0
}

def sum[A](lst: List[A])(implicit m: Additive[A]) = lst.foldLeft(m.zero)((x, y) => m.plus(x, y))
```

実行例)

```Scala
scala> sum(List(1, 2, 3))
res0: Int = 6

scala> sum(List("S", "w", "i", "f", "t"))
res1: String = Swift
```

この用法は、Scalaの標準ライブラリにも使われており、

```Scala
scala> List(1, 2, 3, 4).sum
res0: Int = 10

scala> List(1.5, 2.5, 3, 4).sum
res1: Double = 11.0
```

のように、整数や浮動小数点数の合計値を気にすることなく計算することができる。
このように、型クラスを定義・使用することを可能にするために使うことで、コード設計の幅が広がる。

## おわりに

内容を振り返ってみて、Scalaの基礎文法などを一通り学ぶことができました。これからも、後から見直しやすいようにまとめていくことは続けていきたいと思います。

本記事は、
[Scala研修テキスト](https://dwango.github.io/scala_text/)よりライセンス[CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/deed.ja)に基づき、内容をまとめさせていただきました。