Scala自分用メモ








## ScalaのSeqは基本的に不変のコレクション
<li>値を追加したいときは、seq :+ <追加したい値> のようにして、要素が追加された新しいSeqを作成する

## 索引型・非索引型検索
<li>索引型検索　あらかじめ作られた索引をもとに検索（"word" -> P1, P24)
<li>非索引型検索　与えられた検索パターンを対象全てに試して検索　

map関数の引数で、_.とすると、自身のメソッドを呼び出せる
```sbtshell
scala> val testList = Seq("Oh", "Nagashima")
testList: Seq[String] = List(Oh, Nagashima)

scala> testList.map(_.slice(0,2))
res0: Seq[String] = List(Oh, Na)
```

## String型.r で正規表現のRegex型に変換できる
<String>.r.findAllIn(<検索対象>) で、MatchIterator型のオブジェクト取得


## コンストラクタ引数は、 val や var という変数宣言を与えてやることで、インスタンスから呼び出すことができる

## def hogehoge(num: Int): Unit = ??? このように書くと、メソッドの中身書いていなくてもコンパイルできる

## extends Appをつけると、intellij上でRunできるようになる

## objectキーワードを使って、「クラスのインスタンス化」ではない方法でオブジェクトを呼び出してフィールドやメソッドを利用することができる
```scala
class Dog(name: String) {
  def greet(): Unit = println(s"${name}だワン")
}

object Taro extends Dog("タロウ")

```

## ファクトリメソッド（applyメソッドを使ったクラスのインスタンスを生成するメソッド）で、コンストラクタ引数の型を変えたりしてインスタンス作成の方法を複数設定できる
```scala
class Dog(private val name: String) {
  def greet(): Unit = println(s"${name}だワン")
  override def toString = s"${name}という名前の犬です"
}


object Dog { // ファクトリメソッド（クラスのインスタンスを生成するメソッドのこと）
  
  def apply(name: String) = new Dog(name)
  
  def apply(id: Int) = new Dog(s"番号付き犬${id}番")
  
  def printName(dog: Dog): Unit = println(dog.name)
}
```


```sbtshell
scala> val taro = Dog("タロウ")   ＜＜ val taro = new Dog("タロウ")　と同じ処理
taro: Dog = タロウという名前の犬です　　＜＜ Stringを渡すと、1つ目のapplyが適用される

scala> val dog3 = Dog(3)
dog3: Dog = 番号付き犬3番という名前の犬です   ＜＜ Intを渡すことで、2つ目のapplyが適用された

```
<li>クラスと同名のオブジェクトのことを「コンパニオンオブジェクト」と呼ぶ。
<li>コンパニオンオブジェクトは、同名クラスのプライベートメンバーにアクセス可能

ちなみに、intelliJでは、クラスのスコープ内で右クリック　Generate　-> toString()から簡単にtoStringを定義できる

# ケースクラス


```scala
class Point(val x: Int, val y: Int) {

  override def toString = s"Point($x, $y)"
}
object Point {
  def apply(x: Int, y: Int) = new Point(x, y)
}
```
は、以下で簡単に書き換えられる。
```scala
case class CPoint(x: Int, y: Int)
```

<li>toStringも勝手に、"クラス名（attribute1, attribute2 ...)"という形式で定義してくれる
<li>newをつけなくても、val point1 = Point(2, 3)という形でインスタンス生成できる（objectの定義や、その中でのapplyメソッドの実装不要）
<li>valが不要（勝手にメンバーを公開）

　　※　var で宣言するような更新可能な属性は持たない。値を変えた新しいオブジェクトを生成するには、copyメソッドを使う。

```sbtshell
val cp1 = CPoint(5, 6)
val cp2 = cp1.copy(7, 8)
val cp3 = cp2.copy(y = 9)
```

## クラスとケースクラスでは、同値性の判断が異なる

```sbtshell
scala> val c1 = new Point(1, 2)
val c2 = new Point(1, 2)
val c3 = new Point(3, 4)
println("c1 == c1: " + (c1 == c1))
println("c1 == c2: " + (c1 == c2))
println("c1 == c3: " + (c1 == c3))
c1: Point = Point(1, 2)

scala> c2: Point = Point(1, 2)

scala> c3: Point = Point(3, 4)

scala> c1 == c1: true

scala> c1 == c2: false   // クラスの場合は、値があっていたとしても、別のインスタンスなのでfalse

scala> c1 == c3: false

scala> val cc1 = new CPoint(1, 2)
val cc2 = new CPoint(1, 2)
val cc3 = new CPoint(3, 4)
println("cc1 == cc1: " + (cc1 == cc1))
println("cc1 == cc2: " + (cc1 == cc2))
println("cc1 == cc3: " + (cc1 == cc3))
cc1: CPoint = CPoint(1,2)

scala> cc2: CPoint = CPoint(1,2)

scala> cc3: CPoint = CPoint(3,4)

scala> cc1 == cc1: true

scala> cc1 == cc2: true  // ケースクラスの場合は、値のみを見て同値性を判断するので、true

scala> cc1 == cc3: false
```

ちなみに、クラスでも、IDEを使ってGenerate -> equals() and hashCode() からケースクラスと同じ挙動をとるよう設定できる

## モジュール間の依存関係は、一方向のほうがよい。柔軟性のため。

## package object
パッケージオブジェクトに実装したメソッドは、同じパッケージ内であれば、import文なしで、呼び出せる
（パッケージオブジェクトの名前は、パッケージと同じにする）

## まとめてimport
```scala
import jp.co.dwango.marubatsu.board.CellState
import jp.co.dwango.marubatsu.board.Empty
import jp.co.dwango.marubatsu.board.Maru
import jp.co.dwango.marubatsu.board.Batsu
```
以上は以下のように省略できる
```scala
import jp.co.dwango.marubatsu.board.{CellState, Empty, Maru, Batsu}
```

## アクセス修飾子まとめ
| アクセス修飾子 | 意味 |
|:-----------|:------------|
| private | 自クラス及びコンパニオンオブジェクトからアクセスできる |
| private[this] | 自クラスの同一のインスタンスからのみアクセスできる |
| private[パッケージ名/クラス名] | 指定されたパッケージ/クラスからアクセスできる |
| protected | 自クラスまたはサブクラスからアクセスできる |
| protected[this] | 自クラスまたはサブクラスの同一インスタンスからアクセスできる|
| protected[パッケージ/クラス名]| 指定したパッケージ/クラスであるサブクラスからアクセスできる|

## トレイト　　（「特性、特色」という意味）  (抽象クラスとの違い)
<li>クラスの定義で、複数のトレイトをミックスインすることができる <=> 抽象クラスは、複数を継承させることはできない
<li>コンストラクタを持つことはできない　<=> 抽象クラスは、クラスなので当然コンストラクタを定義できる

```scala
trait Fillable {
  def fill(): Unit = println("Fill!")
}

trait Disposable {
  def dispose(): Unit = println("Dispose!")
}


class Paper

class PaperCup extends Paper with Fillable with Disposable {

}
```

<li> 直接インタンス化はできない（「特性」そのものは、具象化できない）

```scala
val f = new Fillable()　　エラー
```

ただし、{}をつけて（中に定義を書くこともできる）、匿名内部クラスとしてインスタンス化することは可能

```scala
val fff = new Fillable(){}
```

## 菱型継承問題
複数のトレイトをミックスインさせる際、同名のメソッドなどが衝突するしてしまう問題。
Scalaでは、コンパイル時にエラーを出す。

対処法
<li> ミックスインさせる際に、衝突しているメソッドをoverrideする
<li> 衝突しているトレイトのメソッド定義時に、override をつける。そうすると、線形化機能が働き、with句の一番最後のトレイトのメソッドが採用される。


## 複数のモジュールで共通のインスタンスを扱うとき
オブジェクトやクラス、機能別でファイルを分ける際のデザイン

例：　動画プレイヤーのプロジェクトについて、柔軟性を高めるため、可読性を高めるためのリファクタリングとしてファイルを以下のように分ける。
<li>動画一覧のテーブルを司るモジュール
<li>再生、停止を扱うモジュール
<li>マウスイベントハンドラ

しかし、動画プレイヤー全体として操作したいインスタンス（動画プレイヤーインスタンス、テーブルインスタンスなど）
は、当然「同じ」オブジェクトである。

つまり各モジュールでインスタンスを生成することは絶対に避ける必要がある。

そうしたときに、インスタンスにアクセスする方法として、
### 引数にオブジェクトインスタンスをとるメソッドを実装する
という方法がある。（というかこれ以外にない？）