「Scalaスケーラブルプログラミング」まとめ ~ 2章&3章 ~

## この記事は？
[Scalaスケーラブルプログラミング第3版](https://www.amazon.co.jp/Scala%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%A9%E3%83%96%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E7%AC%AC3%E7%89%88-Martin-Odersky/dp/4844381490)を読んで、個人的に気になった箇所や勉強になった箇所のまとめです。
認識誤りなどがあればご指摘いただけると幸いです。

１章のまとめは[こちら](https://qiita.com/tofu511/items/bcc17ca59adbff1e0a42)

## 第2章 Scalaプログラミングの第一歩

### 変数は2種類ある

```var``` は何度でも代入可能な変数。
```val``` は初期化後別の値を代入できない変数。

### 関数定義の仕方
基本的には以下のように定義するが、省略可能なものもある。
関数が１文のみの場合中カッコは省略できる。

Javaではメソッドが返す値の型を「戻り値(return type)」と言うが、Scalaでは「結果型(result type)」と呼ぶ。

```scala
def  max(x: Int, y: Int): Int = {
  if (x > y)
     x
  else
     y
}
```

### 関数が意味のある値を返さない場合Unit型が返る
Unit型はJavaのvoidに似ており、Javaのvoidを返すメソッドはUnitを返すメソッドにマッピングされる。

```scala
scala> def greet() = println("Hello, World!")
greet: ()Unit
```

### 配列の要素にアクセスするときは```()```を使う
Javaでは配列の要素にアクセスする場合は```[]```を使用するがScalaでは```()```を使用する

```scala
// これはJava
String hoge = args[0]

// これはScala
val hoge = args(0)
```

### ```while```と```if```は基本的にJavaと同じ
以下のようにScalaの```while```と```if```は基本的にJavaと同じ

```scala
var i = 0
while (i < args.length) {
	if (i != 0)  // Java同様に中カッコを省略することもできる
		print(" ")
	print(args(i))
	i += 1
}
```

### ```foreach```は関数リテラル、右矢印、関数本体を使う
関数リテラルの構文は以下のように関数パラメータ、右矢印、関数本体の3つからなる

```scala
(x: Int, y: Int) => x + y
```

下の例では```arg```が関数リテラルで```println(arg)```が関数本体である。

```scala
// 例
args.foreach(arg => println(arg))
```

また関数リテラルが１個の引数をとる１文から成る場合は引数を省略できる

```scala
args.foreach(println)
```

### ```for式```では```<-```を使う

```scala
// 例
for (arg <- args)
   println(arg)
```

上の例の```arg```は必ず```val```になる。

```<-``` は「in」と読むと理解しやすいかもしれない。

```python
for (arg in args)
```

## 第3章 Scalaプログラミングの次の一歩

### Scalaでは```new```を使ってインスタンスを生成できる
インスタンスを生成する際に型を指定することもできる

```scala
val hoge = new Array[String](3)
```

### Scalaではすべての演算がメソッド呼び出し

```1 + 2``` は```(1).+(2)```と同じで```1```の```+```メソッドを呼び出し引数に```2```を渡している

配列の要素アクセスや初期化も同様にメソッドを呼び出している

```scala
// 要素アクセス
hoge(0) と hoge.apply(0) は同じ
hoge(0) = "piyo" と hoge.update(0, "piyo") は同じ

// 初期化
val numNames = Array("zero", "one", "two") は
val numNames = Array.apply("zero", "one", "two") と同じ
```



### ScalaのListはイミュータブルである
リストの内容を変更するようなメソッドを呼ぶと、新しい値を持つ新しいリストが作成され、返される。

例えば```::```はリストの先頭に新しい要素を追加して得られるリストを返す。

```scala
scala> val oneTwoThree = 1 :: 2 :: 3 :: Nil
oneTwoThree: List[Int] = List(1, 2, 3)
```

ちなみにListを初期化する場合は最後に```Nil```をつける必要がある。

```scala
scala> val oneTwoThreeFour = 1 :: 2 :: 3 :: 4
<console>:7: error: value :: is not a member of Int
       val oneTwoThreeFour = 1 :: 2 :: 3 :: 4
                                         ^

scala> val oneTwoThreeFour = 1 :: 2 :: 3 :: 4 :: Nil
oneTwoThreeFour: List[Int] = List(1, 2, 3, 4)
```

### タプル(tuple)はリスト同様イミュータブルだが、異なる方の要素を持つことができる

タプルの個々の要素にアクセスするには```._```と1から始まる要素の番号を指定する

```scala
scala> val messi = ("Barcelona", 10)
messi: (String, Int) = (Barcelona,10)

scala> messi._1
res14: String = Barcelona

scala> messi._2
res15: Int = 10
```

### 集合(Set)とマップ(map)にはミュータブルなものとイミュータブルなものがある

Setはデフォルトだとイミュータブルになる

```scala
//デフォルトだとイミュータブルなSetインスタンスが返る
scala> var realMadrid = Set("Ronald", "Ramos", "Isco", "Modric")
realMadrid: scala.collection.immutable.Set[String] = Set(Ronald, Ramos, Isco, Modric) 

// 新しい要素を追加するとイミュータブルなSetの場合、新しいインスタンスを返す
scala> realMadrid + "Kroos"
res16: scala.collection.immutable.Set[String] = Set(Ronald, Kroos, Ramos, Modric, Isco)

// 元のインスタンスの要素は変わっていない
scala> realMadrid
res17: scala.collection.immutable.Set[String] = Set(Ronald, Ramos, Isco, Modric)
```

ミュータブルなSetを使うにはimportが必要

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

scala> val bigFour = mutable.Set("Federer", "Nadal", "Djokovic")
bigFour: scala.collection.mutable.Set[String] = Set(Djokovic, Nadal, Federer)

scala> bigFour += "Murray"
res18: bigFour.type = Set(Djokovic, Nadal, Murray, Federer)

scala> bigFour
res19: scala.collection.mutable.Set[String] = Set(Djokovic, Nadal, Murray, Federer)
```

Mapもデフォルトはイミュータブルで、ミュータブルなMapを作るにはimportする必要がある。

```scala
scala> val artists = Map(1 -> "Suchmos", 2 -> "BUMP OF CHICKEN", 3 -> "Utada Hikaru") 
artists: scala.collection.immutable.Map[Int,String] = Map(1 -> Suchmos, 2 -> BUMP OF CHICKEN, 3 -> Utada Hikaru)
```
```scala
scala> import scala.collection.mutable
import scala.collection.mutable

scala> val rappers = mutable.Map(1 -> "Jay-Z", 2 -> "Nas")
rappers: scala.collection.mutable.Map[Int,String] = Map(2 -> Nas, 1 -> Jay-Z)

scala> rappers += (3 -> "Q-Tip")
res20: rappers.type = Map(2 -> Nas, 1 -> Jay-Z, 3 -> Q-Tip)

scala> rappers
res21: scala.collection.mutable.Map[Int,String] = Map(2 -> Nas, 1 -> Jay-Z, 3 -> Q-Tip)
```

### 関数型のスタイルに近づくには```var```を使わないことが大事
```scala
// これは命令型スタイル
def printArgs(args : Array[String]): Unit = {
  var i = 0
  while(i < args.length) {
    println(args.(i))
    i += 1
  }
}

// これは関数型スタイル(純粋な関数型ではない!)
def printArgs(args : Array[String]): Unit = {
  args.foreach(println)
}
```

**純粋**な関数型は**副作用**を持たない。結果型が```Unit```になっていると副作用があることを意味している。