Scalaプログラミング

## 概要

Scalaとは、2003年にリリースされた、関数型プログラミングとオブジェクト指向双方に対応可能なハイブリッド言語です。

- 関数型プログラミング
- オブジェクト指向

## 環境構築

- JDK 1.8 インストール
- Scala 2.12.11 インストール
   1. https://www.scala-lang.org/ 
   2. DOWNLOAD
   3. Other release
   4. scala-2.12.11.zip
   5. 解凍
   6. 環境変数設定
   7. テストコマンドプロンプトで'scala'
    ```
    Welcome to Scala 2.12.11 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_172).
    Type in expressions for evaluation. Or try :help.
    ```

## HelloScala

- 新規HelloScala.scala
```
object HelloScala{
	def main(args: Array[String]):Unit = {
		println("hello scala")
	}
}
```
- コマンドプロンプト起動
- `scalac HelloScala.scala`実行
- HelloScala.classとHelloScala$.classが作成される
- コマンド`scala HelloScala`
  
## IDE
IDEのIntelliJ使用と設定
- IntelliJ IDEA Community(https://www.jetbrains.com/ja-jp/idea/download/#section=windows)
- New Maven Project:File->Maven->Next->Finish 
- scala plugin:File->Setting->Plugin->scala
- project右クリック->Add Framework Support->Scala->Configure（Scala環境設定）->OKボタン

HelloWord
- [src->main]の下に[scala]フォルダを新規
- [scale]フォルダの下にpackageを新規
- NewでObjectを選択しHelloWordを新規

関数
`def 関数名(引数:型):戻り値={処理}`

## 変数

### 注釈

1. 一行 `\\`
2. 複数 `\**\`
3. scaladoc注釈 
   ```scala
   /**
    * 
    */
   ```
### 変数定義

- 変数:`var 変数名[:型] = 初期値` 
  例 `var i:Int=20`
- 定数:`val 定数名[:型] = 初期値`
  例 `val j:Int=10`

注意：初期値が必須

### 文字列
定義
`val 名前[String]="値"`

出力
- 結合:`+`
  複数回コピー`*`
- printf:C/C++のような書き方
  `printf("%d%s",age,str)`
- 文字列の補間:文字列リテラルの先頭に`s`を追加することで文字列の中で直接変数が使えるようになる。
  ```scala
  val name = "James"
  println(s"Hello, ${name}")  // Hello, James 
  ```

### 入力
キーボードから入力を読み込む
- `scala.io.StdIn`オブジェクトを利用
  - `StdIn.readLine()`
  - `StdIn.readShort()`
  - `StdIn.readDouble()`

- `scala.io.Source`オブジェクトのstdinメソッドを利用
  ```scala
  line <- io.Source.stdin.getLines()
  ```
- `java.util.Scanner`クラスを利用
  ```scala
  val scanner = new java.util.Scanner(System.in)
  ```

ファイルから読み込む
`scala.io.Source.fromFile("ファイルパス")`

### 基本の型
Scalaでは他のプログラミング言語と同様に数値や文字など基本的な値を扱う仕組みが用意されています。

- Byte:-128 から 127
- Short:-32768 から 32767
- Int:-2147483648 から 2147483647
- Long:-9223372036854775808 から 9223372036854775807
- Float:32ビットのIEEE 754単精度浮動小数点
- Double:64ビットのIEEE 754倍精度浮動小数点
- Char:16ビット符号なしUnicode文字
- Boolean:true または false
- String:Charのシーケンス

キャスト
- Byte ---> Short ---> Int ---> Long ---> Float ---> Double
- Char ---> Int 
- CharとByte,Shortキャストができない

Scalaの基本の型はすべてオブジェクトである

[参考](https://scalapedia.com/articles/119/%E5%9F%BA%E6%9C%AC%E3%81%AE%E5%9E%8B%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%A7%A3%E8%AA%AC#:~:text=Scala%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%AE%E5%9E%8B%E3%81%AF%E3%81%99%E3%81%B9%E3%81%A6%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A7%E3%81%82%E3%82%8B&text=Any%20%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AF%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE,%E3%81%AF%20AnyVal%20%E3%81%AE%E5%AD%90%E4%BE%9B%E3%81%A7%E3%81%99%E3%80%82)

Javaの型との対比
ScalaにはJavaのプリミティブ型に該当するものはありません。
以下のように基本の型がJavaのプリミティブ型およびそれらのラッパークラスに該当します。
|  Scala 基本の型  |  Java プリミティブ型  |  Java ラッパークラス  |
| ---- | ---- | ---- |
| Byte | byte | Byte |
| Short | short | Short |
| Int | int | Integer |
| Long | long | Long |
| Float | float | Float |
| Double | double | Double |
| Char | char | Char |
| Boolean | boolean | Boolean |

### Unit型Null型Nothing型

TODO

## 演算子
基本Javaと同様だが、違うものもあり


|  演算子  |  例  |  説明  |
| ---- | ---- | ---- |
| +-*/%| m + n</br>m - n</br>string + n</br>m * n</br>m / n</br>m % n | 加算・減算・乗算・除算・剰余 |
| ()/{} | (1 + 2)/{1 + 2} | 優先する式 |
| == != | m == n</br>m != n | 等価</br>不等価 |
| < ></br><= >= | m < n</br>m <= n | 大小比較</br>型比較 |
| & | m & n | ビットAND |
| ^ | m ^ n | ビットXOR |
| | | m | n | ビットOR |
| && | b1 && b2 | 条件AND |
| || | b1 || b2 | 条件OR |
| if | if (b) m else n | 条件 |
| ~ | `~n` | ビット否定 |
| ! | !b | 論理否定 |
| << >> | n << r | ビットシフト |
| >>> | n >>> r | 符号無し右ビットシフト |
| =</br>*= /= %=</br>+= -=</br><<= >>= >>>=</br>&= ^= |= | m = n</br>m *= n | 代入 |
| new | new Array[型](n) | 新規生成 |

[参考](https://www.ne.jp/asahi/hishidama/home/tech/scala/expression.html)

## 制御構文

### ブロック式
Scalaでは {} で複数の式の並びを囲むと、それ全体が式になりますが、便宜上それをブロック式と呼ぶことにします。
```scala
{ <式1>(;|<改行>) <式2>(;|<改行>) ... }
```

### if式
if式はJavaのif文とほとんど同じ使い方をします。
```scala
if '('<条件式>')' <then式> (else <else式>)?
```

```scala
var age = 17
// age: Int = 17

if(age < 18) {
  "18歳未満です"
} else {
  "18歳以上です"
}
// res1: String = "18歳未満です"

age = 18

if(age < 18) {
  "18歳未満です"
} else {
  "18歳以上です"
}
// res3: String = "18歳以上です"
```

```scala
val result = if(age >=18) "成人" else "未成年"
```

### for式
for 式の基本的な構文は次のようになります。
```scala
for '(' (<ジェネレータ>;)+ ')' '<本体>' 
# <ジェネレータ> = x <- <式>
```

```scala
for(i <- 1 to 5){
  println("i = " + i)
}
println("**************************")
for(j:Int <- 1.to(5)){
  println("j = " + j)
}

```

ループの中のループ
```scala
println("**************************")
for(x <- 1 to 5; y <- 1 until 5){
  println("x = " + x + " y = " + y)
}
// x = 1 y = 1
// x = 1 y = 2
// x = 1 y = 3
// x = 1 y = 4
// x = 2 y = 1
// x = 2 y = 2
// x = 2 y = 3
// x = 2 y = 4
// x = 3 y = 1
// x = 3 y = 2
// x = 3 y = 3
// x = 3 y = 4
// x = 4 y = 1
// x = 4 y = 2
// x = 4 y = 3
// x = 4 y = 4
// x = 5 y = 1
// x = 5 y = 2
// x = 5 y = 3
// x = 5 y = 4
```
リストのループ
```scala
for(i <- Array(0,1,4)){
  println(i)
}
println("**************************")
for(i <- Set(1,5,12)){
  println(i)
}
```
ループ中の条件
for式の力はこれだけではありません。ループ変数の中から条件にあったものだけを絞り込むこともできます。untilの後で`if x != y`と書いていますが、これは、xとyが異なる値の場合のみを抽出したものです。scalaの中には`continue`がありません。
```scala
for(x <- 1 to 5; y <- 1 until 5 if x != y){
  println("x = " + x + " y = " + y)
}
// x = 1 y = 2
// x = 1 y = 3
// x = 1 y = 4
// x = 2 y = 1
// x = 2 y = 3
// x = 2 y = 4
// x = 3 y = 1
// x = 3 y = 2
// x = 3 y = 4
// x = 4 y = 1
// x = 4 y = 2
// x = 4 y = 3
// x = 5 y = 1
// x = 5 y = 2
// x = 5 y = 3
// x = 5 y = 4
```

ステップ
for文ステップの設定(`i++/i--/i=i+2`)

```scala
for(i <- 1 to 10 by 2){
  println(i)
}
println("**************************")
for(i <- (1 to 10).by(2)){
  println(i)
}
println("**************************")
for(i <- (10 to 1).by(-1)){
  println(i)
}
```

stepが0場合は`IllegalArgumentException`エラー
```scala
for(i <- (10 to 1).by(0)){
  println(i)
}

Exception in thread "main" java.lang.IllegalArgumentException: step cannot be 0.
	at scala.collection.immutable.Range.<init>(Range.scala:87)
	at scala.collection.immutable.Range$Inclusive.<init>(Range.scala:442)
	at scala.collection.immutable.Range$Inclusive.copy(Range.scala:445)
	at scala.collection.immutable.Range.by(Range.scala:132)
	at chapter04.Test02_ForLoop$.main(Test02_ForLoop.scala:37)
	at chapter04.Test02_ForLoop.main(Test02_ForLoop.scala)
```

一時変数の使用
```scala
for(i <- 1 to 10; j = 10 - i){
  println("i = " + i + ", j = " + j)
}
```

戻り値
ディフォルト戻り値は`Unit`(空)である。`yield`は戻り値を設定する
リストに対する何かの処理ができる
```scala
var b = for(i <- 1 to 10) yield i
println("b = " + b)
b = for(i <- 1 to 10) yield i*2
println("b = " + b)
```


### while式
while式の構文はJavaのものとほぼ同じです。do while 式もあります。
while文の外部にインデックスが定義することが必要のため、Scalaではwhile文がおすすめしない。
```scala
while '(' <条件式> ')' 本体式
```

```scala
var i = 1
// i: Int = 1

while(i <= 10) {
  println("i = " + i)
  i = i + 1
}
// i = 1
// i = 2
// i = 3
// i = 4
// i = 5
// i = 6
// i = 7
// i = 8
// i = 9
// i = 10

do {
  println("i = " + i)
  i = i + 1
}while(i <= 10)
```

### 中断
Javaの break 文や continue 文に相当する言語機能はありません。しかし、後ほど説明する高階関数を適切に利用すれば、ほとんどの場合、 break や continue は必要ありません。

throwで中断
Scalaでは`throw Exception`でループを中断させる
```scala
try{
  for(i <- 0 to 10){
    if(i == 5)
      throw new RuntimeException
    println(i)

  }
}catch {
  case e:Exception =>
}
```

Breaks中断
`Breaks.breakable`はtry/catchのラッパー関数である。`Breaks.break()`は`throw breakException`の処理だ。
```scala
Breaks.breakable(
  for(i <- 0 to 10){
    if(i == 5)
      Breaks.break()
    println(i)

  }
)
```

## 関数型プログラミング
f(x) = x+1

```scala
def sum( x : Int, y : Int ) : Int = {
  x + y
}
```
関数の省略
以下のものは省略できる
- 戻り値の型：戻り値の型を省略する場合は、必ずreturnも省略する。need result type error
- return
- 括弧`{}`
- `=`：戻り値がUnitの場合は、`={}`の`=`も省略できる
- `()`：変数が無い場合は、`()`も省略できる
- 関数名と`def`：関数は`=>`を使用（無名関数またはlambda式）

無名関数
```scala
def add(x: Int, y: Int) : Int = {
  return x + y
}
println(add(1,2))
println("***************")
val add_val = (x: Int, y: Int) => x + y
println(add_val(1,2))
```

関数のカリー化
Int => Int => Int 型の関数のように、1つの引数を取り、残りの引数を取る関数を返す関数のチェインで表現するというものです。
```scala
val add = (x: Int, y: Int) => x + y
// add: (Int, Int) => Int = <function2>

val addCurried = (x: Int) => ((y: Int) => x + y)
// addCurried: Int => Int => Int = <function1>

add(100, 200)
// res2: Int = 300

addCurried(100)(200)
// res3: Int = 300
```

高階関数

関数を引数に取ったり関数を返すメソッドや関数のことを高階関数と呼びます。先ほどメソッドと関数の違いについて説明したばかりなのに、メソッドのことも関数というのはいささか奇妙ですが、慣習的にそう呼ぶものだと思ってください。
ある関数を引数として別の関数に代入する

```scala
val increment = (x:Int) => {
  println("increment = "+x)
  x + 1
}
def double(n: Int, fun: Int => Int): Int = {
  fun(fun(n))
}
println(double(n = 1,increment))
```

値としての渡し
```scala
def add(x:Int):Int = {
  println("add")
  x + 1
}
val f1:Int => Int = add
val f2 = add _
println(f1)
println(f1(12))
println(f2)
println(f2(12))
```

引数としての渡し

```scala
def dualEval(fun:(Int,Int)=>Int,x:Int,y:Int):Int = {
  fun(x,y)
}
val val_minus = (x:Int,y:Int) => x - y
println(dualEval(val_minus,10,2))
```

関数の戻り値
```scala
def returnFun():Int=>Unit ={
  def printFun(x:Int):Unit = {
    println("x = " + x)
  }
  printFun
}

val printFun = returnFun()

returnFun()
printFun(10)
returnFun()(35)
```

## オブジェクト指向

package
特別書き方`{}`
- 一つファイルの中に複数のpackage定義できる
- サブpackageが`import`せず直接親packageをアクセスできる
```scala
package com{
  package abc{
    package projectA{

    }
  }
}
```
packageのオブジェクト
オブジェクトにメンバー変数また関数が定義できる。package中にすべてのクラスがアクセスできる共通なもの

パッケージオブジェクト
```scala
package object chapter06 {
  def commonFunction():Unit = {
    println("commonFunction")
  }
  val commonValue:Int = 12
}

```
アクセス
```scala
package chapter06
object Test02_PackageObject {
  def main(args: Array[String]): Unit = {
    commonFunction()
    println(commonValue)
  }
}
```

クラス
```scala
object Test_Class{
    def main(args: Array[String]):Unit ={
        var st1:Student = new Student()
        println(st1.age)
        println(st1.gender)
        println(st1.high)
    }
}

class Student{
    var name: String = "alice"
    @BeanProperty
    var age: Int = 18
    var gender: String = "male"
    var school: String = _ // 空
    var high: Int = _ // 空
}
```

パッケージ化

`@BeanProperty`注釈

コンストラクター
```scala
class Person(first: String, last: String) {
  val firstName = first
  val lastName = last
  def name = firstName + " " + lastName
}
```

```scala
val dave = new Person("Dave", "Gurnell")
// dave: Person = Person@258c10ba

dave.name
// res5: String = Dave Gurnell
```

継承
Javaのクラスと同様、継承することができます。
```scala
class <クラス名> <クラス引数> (extends <スーパークラス>)? (with <トレイト名>)* {
  (<フィールド定義> | <メソッド定義>)*
}
```

### トレイト
トレイトはクラス間でインターフェースとフィールドを共有するために使います。
```scala
trait <トレイト名> {
  (<フィールド定義> | <メソッド定義>)*
}
```

トレイトはクラスに比べて以下のような特徴があります。
- 複数のトレイトを1つのクラスやトレイトにミックスインできる
- 直接インスタンス化できない
- クラスパラメータ（コンストラクタの引数）を取ることができない


複数のトレイトを1つのクラスやトレイトにミックスインできる

```scala
object Test06_Trait {
  def main(args: Array[String]): Unit = {
    var classC:ClassC = new ClassC()
    classC.age = 12
    classC.name = "tom"
    println(s"aga=${classC.age} name=${classC.name}")
  }
}

trait TraitA{
  println("TraitAコンストラクタ")
  var name:String = _
}

trait TraitB{
  println("TraitBコンストラクタ")
  var age:Int = _
}

trait TraitC{
  def printInfo():Unit={
    println("TraitC")
  }
}

class ClassA{
  println("ClassAコンストラクタ")
}
class ClassB{
  println("ClassBコンストラクタ")
}

class ClassC extends ClassA with TraitA with TraitB{
  println("ClassCコンストラクタ")
}
```

直接インスタンス化できない
トレイトが単体で使われることをそもそも想定していないための制限です。トレイトを使うときは、通常、それを継承したクラスを作ります。

```scala
trait TraitA{
  println("TraitAコンストラクタ")
  var name:String = _
}

object Test06_Trait02 {
  def main(args: Array[String]): Unit = {
    val a = new TraitA
    // コンパイルエラー
      
    val a = new ClassA
    // クラスにすればインスタンス化できる
  }
}
```

クラスパラメータ（コンストラクタの引数）を取ることができない

```scala
// 正しいプログラム
class ClassA(name: String) {
  def printName() = println(name)
}

// コンパイルエラー！
trait TraitA(name: String)
```

動的Trait
```scala
object Test06_Trait02 {
  def main(args: Array[String]): Unit = {
    val dd = new ClassD with TraitD{
      override def play(): Unit = println("TraitD play")
    }
    dd.play()
  }
}

trait TraitD{
  def play(): Unit
}

class ClassD {
  var name:String = "tom"
  println("ClassDコンストラクタ")
}
```

トレイトの線形化機能

トレイトの継承順番が線形化されて、後からミックスインしたTraitが優先されているためです。以下のコードの場合、トレイトのミックスインの順番は、`TraitB with TraitC`の`TraitC`が優先されるようになります。右から左が優先されます。
```scala
object Test07_TraitLinearization {
  def main(args: Array[String]): Unit = {
    (new ClassA).greet()
    // TraitC Good evening!
    (new ClassB).greet()
    // TraitB Good morning!
  }
}

trait TraitA {
  def greet(): Unit
}

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

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

class ClassA extends TraitB with TraitC
class ClassB extends TraitC with TraitB
```

菱形継承問題
```scala
object Test06_Trait04 {
  def main(args: Array[String]): Unit = {
    (new ClassA).greet()
    // TraitC TraitB Good morning!
  }
}

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

trait TraitB extends TraitA {
  var nameB:String = "TraitB"
  override def greet(): Unit = {
    print(nameB + " ")
    super.greet()
  }
}

trait TraitC extends TraitA {
  var nameC:String = "TraitC"
  override def greet(): Unit = {
    print(nameC + " ")
    super.greet()
  }
}

class ClassA extends TraitB with TraitC
```
`class ClassA extends TraitB with TraitC`クラスの継承順番は、ClassA -> TraitC -> TraitB -> TraitAのため、`TraitC TraitB Good morning!`が出力される

traitとabstract
- traitがおすすめ
- コンストラクタ（メンバー変数）が使用する場合、abstract使用

依存性の注入

`_:User =>`は、`UserDAO`が依存`User`注入

```scala
object Test07_TraitSelftype {
  def main(args: Array[String]): Unit = {
    var userReg:UserRegister = new UserRegister("tom","123")
    userReg.insert()
  }
}

class User(val name:String,val password:String)

trait UserDAO{
  _:User =>

  def insert(): Unit ={
    println(s"insert ${this.name} to database")
  }
}

class UserRegister(name:String,password:String) extends User(name,password) with UserDAO
```

## コレクション（collection）
Scala のコレクションは、体系的に可変および不変コレクションを区別している。[参考](https://docs.scala-lang.org/ja/overviews/collections/overview.html)
- Seq
- Set
- Map

### 不変コレクション
Arrayの定義
```scala
val arr1:Array[Int] = new Array[Int](10)
var arr2 = Array(1,2,3,4)
```
Arrayのアクセス
```scala
arr1(0) = 99

for(i <- arr1.indices ){
  print(arr1(i) + " ")
}

for(elem <- arr1) print(elem + " ")

val iter = arr1.iterator
while(iter.hasNext) print(iter.next() + " ")

arr1.foreach((elem:Int) => print(elem+" "))
arr1.foreach(print(_))
```

Arrayの追加
```scala
var arr2 = Array(11,12,13,14)
println(arr2.mkString("-"))
val arr3 = arr2.:+(99)// 後尾に追加
println(arr3.mkString("-"))
val arr4 = arr2.+:(0)// 先頭に追加
println(arr4.mkString("-"))

val arr5 = arr2 :+ 99 // 先頭に追加
println(arr5.mkString("-"))
val arr6 = 0 +:  arr2// 先頭に追加
println(arr6.mkString("-"))
val arr7 = -1 +: 0 +: arr2// 先頭に追加
println(arr7.mkString("-"))
```

Listの定義
```scala
val list1 = List(4,5,6)
```

Listの追加
```scala
val list2 = list1 :+ 7
val list3 = 3 +: list1
val list4 = 7 :: list1// list1.::(7,8,9)
val list5 = 1 :: 2 :: 3 :: Nil
println(list2.mkString(",")) // 4,5,6,7
println(list3.mkString(",")) // 3,4,5,6
println(list4.mkString(",")) // 7,4,5,6
println(list5.mkString(",")) // 1,2,3
```

`:::`または`++`二つリストの結合
```scala
val list6 = list2 ::: list3 // ++
println(list6.mkString(","))// 4,5,6,7,3,4,5,6
```

Set
- 無順
- 重複不可

Set定義
```scala
val set1 = Set(3,2,1,4) 
println(set1)// Set(3, 2, 1, 4)
```

Set要素追加
```scala
val set2 = set1.+(-1)
val set3 = set1 + 23
println(set2)// Set(1, 2, 3, -1, 4)
println(set3)// Set(1, 2, 3, 23, 4)
```

Set要素削除
```scala
val set5 = set1 - 1
val set6 = set1.-(1)
println(set5)// Set(3, 2, 4)
println(set6)// Set(3, 2, 4)
```

Set結合
```scala
val set7 = set2 ++ set3
println(set7)
```

Map
```scala
val map1:Map[String,Int] = Map("a" -> 97,"b" -> 98,"c" -> 99)

map1.foreach(println)

for(key <- map1.keys){
  println(s"${key},${map1.get(key).get}")
}

// Keyからのアクセス
println(s"a = ${map1.get("a").get}") // a = 97
println(s"a = ${map1.getOrElse("a",0)}") // a = 97
println(s"e = ${map1.getOrElse("e",0)}") // e = 0
```



### 可変コレクション
ArrayBufferの定義
```scala
val arr_buf1 = new ArrayBuffer() // default size 16
val arr_buf2 = new ArrayBuffer[Int](1)
val arr_buf3 = ArrayBuffer(1,2,3,4)
```

ArrayBufferの追加
- 後尾：`+=` `append()`
- 先頭：`+=:` `prepend()`
- 任意：`insert()`
```scala
val arr_buf4 = arr_buf2 :+ 3
arr_buf2 += 4 // 後尾append()
0 +=: arr_buf2// 先頭prepend()
arr_buf2.append(2)
arr_buf2.prepend(1)
arr_buf2.insert(0,0)
```

ArrayBufferの削除
`remove()`と`-=`削除

```scala
arr_buf2.remove(0)
arr_buf2 -= 0 // 該当数値が無い場合は何もしない
```

Arrayへの変換
```scala
val arr1:Array[Int] = arr_buf2.toArray // ArrayBuffer to Array
val arr_buf5 = arr1.toBuffer// Array to ArrayBuffer
```

ListBufferの定義
```scala
val list_buf1:ListBuffer[Int] = new ListBuffer[Int]()
val list_buf2 = ListBuffer(5,6,7)
```

Set定義
```scala
import scala.collection.mutable

val set1 = mutable.Set(11,13,23,39,5)
println(set1)// Set(13, 5, 39, 11, 23)
```

Set要素追加
`add()`

Set要素削除
`remove()`

Set結合
`++`

Map
Mapの定義
```scala
val map1:mutable.Map[String,Int] = mutable.Map("a" -> 97,"b" -> 98,"c" -> 99)
import scala.collection.mutable
```
Map要素追加
```scala
map1.put("d",100)
map1 += (("e",101))
println(map1)// Map(e -> 101, b -> 98, d -> 100, a -> 97, c -> 99)
```

Map要素削除
```scala
map1.remove("a")
map1 -= "e"
println(map1)// Map(b -> 98, d -> 100, c -> 99)
```

Map結合
```scala
val map2:mutable.Map[String,Int] = mutable.Map("a" -> 97,"b" -> 0,"c" -> 0)
map1 ++= map2 // map2の要素をmap1に上書きで追加
println(map1)// Map(b -> 0, d -> 100, a -> 97, c -> 0)
```

### タプル

複数の型のセットできる
```scala
// タプルの定義
val tuple:(String, Int) = ("文字列", 1)
// タプルから値を取り出す
println(tuple._1)  // 文字列
println(tuple._2)  // 1
```

### コレクションの操作

- サイズ：`length()` `size()`
- 出力：`mkString()`
- 含む判定：`contains()`
- 先頭：`head`
- 後尾（先頭除き）：`tail`
- 後尾（先頭除き）：`last`
- 反転：`reverse`
- 取得（複数）：左`take()` 右`takeRight()`
- 削除（複数）：左`drop()` 右`dropRight()`
- 和集合：`union()`
- 積集合：`intersection()`]
- 同じ位置の要素をペア：`zip`

計算
- 和：`sum`
- 積：`product`
- 最大値：`max`
- 最小値：`min`
- ソート：`sort`

フィルター
`filter`:p: A => Boolean
```scala
val list1 = List(1,2,3,4,5,6,7)
val filter_list1 = list1.filter(_ % 2 == 0)
//val filter_list1 = list1.filter((x : Int) => { x % 2 == 0 })
println(filter_list1)//List(2, 4, 6)
```

マッピング
`map`:f: A => B
```scala
val list1 = List(1,2,3,4,5,6,7)
val filter_list1 = list1.map(_ * 2)
//val filter_list1 = list1.map((x : Int) => { x * 2})
println(filter_list1)
```

平坦化
`flatten`:implicit t: A => Traversable[B]

```scala
val list1:List[List[Int]] = List(List(1,2,3),List(4,5),List(7,8,9))
val flat_list1 = list1(0) ::: list1(1):::list1(2)
println(list1)//List(List(1, 2, 3), List(4, 5), List(7, 8, 9))
println(flat_list1)//List(1, 2, 3, 4, 5, 7, 8, 9)

val flat_list2 = list1.flatten
println(flat_list2)//List(1, 2, 3, 4, 5, 7, 8, 9)
```

要素同士の演算
- 整理reduce
`reduce`:op: (A1, A1) => A1 要素同士を左（先頭）から順に演算する。
```scala
val list1 = List(1,2,3,4,11,12,21)
println(list1)// List(1, 2, 3, 4, 11, 12, 21)
println(list1.reduce((x:Int,y:Int) => x + y))// 54=(1+ 2+ 3+ 4+ 11+ 12+ 21)
```

`reduceRight()`について
```scala
val list1 = List(1,2,11,12)
println(list1)// List(1, 2, 3, 4, 11, 12, 21)
println(list1.reduce((x:Int,y:Int) => x - y))// -24 = 1 - 2 - 11 - 12
println(list1.reduceLeft((x:Int,y:Int) => x - y))// -24 = 1 - 2 - 11 - 12
println(list1.reduceRight((x:Int,y:Int) => x - y))// -2 = 1 - (2 - (11 - 12))
```

- 整理fold
op: (B, A) => B zと要素（左（先頭）から順番）に演算opを行う。
```scala
val list1 = List(1,2,11,12)
println(list1)// List(1, 2, 3, 4, 11, 12, 21)
println(list1.fold(12)((z, n) => z + n)) // 26 = 12 + 1 + 2 + 11 + 12
println(list1.foldLeft(12)((z, n) => z + n)) // 26 = 12 + 1 + 2 + 11 + 12
println(list1.foldRight(12)((z, n) => z + n)) // 26 = 12 + 1 + 2 + 11 + 12

println(list1.fold(3)((z, n) => z - n)) // -23 = 3 - 1 - 2 - 11 - 12
println(list1.foldLeft(3)((z, n) => z - n)) // -23 = 3 - 1 - 2 - 11 - 12
println(list1.foldRight(3)((z, n) => z - n)) // 1 = 1 - (2 - (11 - (12 - 3)))
```

[参考](https://www.ne.jp/asahi/hishidama/home/tech/scala/collection/method.html)

## match
match式は、値に応じて処理を分岐させる。
```scala
値 match {
  case パターン1 => 処理1
  case パターン2 => 処理2
```

```scala
val x:Int = 5
val y:String = x match {
  case 1 => "one" // break不要
  case 2 => "two"
  case 3 => "three"
  case _ => "other" //default
}
println(y)
```
ガード条件（if）
```scala
def count(n: Int) = {
  n match {
    case m if m <  0 => "なにそれ"
    case 0           => "ない"
    case m if m <= 3 => "数えられる"
    case _           => "たくさん"
  }
}
println(count(-1))//なにそれ
println(count(0))//ない
println(count(1))//数えられる
```

マッチした値を取得する

型でマッチ
```scala
def length(obj: Any) = {
  obj match {
    case s:String   => s.length
    case a:Array[_] => a.length
    case l:List[_]  => l.size
    case _ => 0
  }
}

var array1 = Array(1,2,3)
var list1 = List(1,2,3,4)
println(length("abcd":String)) // 4
println(length(array1)) // 3
println(length(list1)) // 4
println(length(1:Int)) // 0
println("************************")
}
```

Arrayマッチ
```scala
def arr(a: Array[Int]) = {
  a match {
    case Array(1,2,3) => 1
    case Array(4,5,6) => 2
    case Array(x,y) => 0
    case Array(0,_*) => 1
  }
}
val arr1 = Array(1,2,3)
val arr2 = Array(4,5,6)
val arr3 = Array(0,2,3)
println(arr(arr1))
println(arr(arr2))
println(arr(arr3))
```

Listマッチ
```scala
def list(l: List[_]) = {
  l match {
    case List(n, other @ _*) =>
      println(n)
      println(other) //“その他全て”を表す「_*」に対して、「@」で変数名を指定できる。
  }
}
def listMatch(l: List[_]) = {
  l match {
    case first :: second :: result => println(s"${first} ${second} ${result}") //少なくとも２つ要素がある
  }
}
val list1 = List(1,2,3,4)
val list2 = List(11,21,31,41)
list(list1)//1 \n List(2, 3, 4)
listMatch(list2)// 11 21 List(31, 41)
```

オブジェクトマッチ
`unapply`関数は1つのオブジェクトを受け取り、引数を返す。パターンマッチングと部分関数で最も頻繁に使われます。

方法１
```scala
class Student(val name:String,val age:Int)
object Student{
  def apply(name:String,age:Int):Student = new Student(name, age)
  def unapply(student: Student):Option[(String,Int)]={
    if(student==null){
      None
    }else{
      Some((student.name,student.age))
    }
  }
}

def main(args: Array[String]): Unit = {
  val stu1 = Student("tom",18)
  val match1 = stu1 match {
    case Student("tom",18) => 1
    case _ => 0
  }
  println(match1)
}
```
方法２
ケースクラス`case class`の宣言。パラメータはパブリックのvalとなります。
```scala
case class Book(isbn: String) // ケースクラス パラメータはパブリックのvalとなります。
def main(args: Array[String]): Unit = {
  val book1 = Book("123456")
  val result1 = book1 match{
    case Book("123456") => 1
    case _ => 0
  }
  val result2 = book1 match{
    case Book("1234") => 1
    case _ => 0
  }
  println(result1)// 1
  println(result2)// 0
}
```

[参考](https://www.ne.jp/asahi/hishidama/home/tech/scala/match.html)

## try/catch

```scala
def main(args: Array[String]): Unit = {
  var text = ""
  try {
    text = openAndReadAFile("")
  } catch {
    case e: FileNotFoundException => println("Couldn't find that file.")
    case e: IOException => println("Had an IOException trying to read that file")
  }finally {
    println("finally")
  }
}
def openAndReadAFile(filename: String) = {
  val lines = Source.fromFile(filename).getLines.toList.toString()
  lines
}

//Couldn't find that file.
//finally
```
## 暗黙の変換
`implicit`で関数定義
```scala
object Test01_ImplicitConversions {
  def main(args: Array[String]): Unit = {
    implicit def convertIntToMyRichInt(num:Int):MyRichInt = {
      new MyRichInt(num)
    }
    val num:Int = 23
    println(num.myMax(2))
    println(num.myMin(0))
  }
}

class MyRichInt(val self:Int){
  def myMax(n:Int):Int = if(self < n) n else self
  def myMin(n:Int):Int = if(self < n) self else n
}
```

暗黙クラス
`implicit class`でクラス定義
```scala
implicit class MyRichIntImplicitClass(val self:Int){
  def myMaxImplicitClass(n:Int):Int = if(self < n) n else self
  def myMinImplicitClass(n:Int):Int = if(self < n) self else n
}

val num2:Int = 1
println(num2.myMaxImplicitClass(2))
println(num2.myMaxImplicitClass(0))
```