がばがばscala独学-クラス(1)

# はじめに

下記のテキストを通して、基本的な書き方を学びつつ、個人的に気になったことを検証していくメモ代わりです。
https://dwango.github.io/scala_text/basic.html
本当にありがとう、dwango様・・・

# クラス

大学の講義程度のJavaをやっていたので前提知識は大丈夫だと思いたい
> 最低限、Javaのクラスがわかっている事を前提にします

ざっくりまとめ

* classは`class ClassName` で定義し、内部にはfield or methodを定義可能で、引数に対してval/varで外部読み出し可能な変数を宣言可能
* methodは `def methodName` で定義可能
* field定義は次回に持越し

## クラス定義
* 一般型

    ```scala
    class ClassName(parameter1: Type1, parameter2: Type2, ...) {
      (a field or method definition)の0回以上の繰り返し
    }
    ```

* 点を表すクラスPointを定義

    * 基本的な定義

        ```scala
        scala> class Point(_x: Int, _y: Int) {
             |   val x = _x
             |   val y = _y
             | }
        defined class Point

        scala> Point(10, 20)
        <console>:8: error: not found: value Point
                      Point(10, 20)
                      ^

        scala> new Point(10, 20)
        res1: Point = Point@1605dc19
        ```
        * class定義をする方法をすっかり忘れていた・・・

    * 定義と公開を両方成す場合

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

        scala> new Point(10, 20)
        res0: Point = Point@513ed3da
        ```
        * コンストラクタの引数をそのまま公開したい場合、一行でOK

    * 外部公開をした場合の処理

        ```scala
        scala> class Point(val x: Int, val y: Int) {
             |   def +(p: Point): Point = {
             |     new Point(x + p.x, y + p.y)
             |   }
             |   override def toString(): String = "(" + x + ", " + y + ")"
             | }
        defined class Point

        scala> val p = new Point(10, 20)
        p: Point = (10, 20)

        scala> println(p.x)
        10

        scala> println(p.y)
        20

        scala> println(p.toString)
        (10, 20)

        ```
        * 複数のコンストラクタが定義できるので、この最初の1つのコンストラクタをプライマリコンストラクタとして特別に扱う
        * プライマリコンストラクタの引数にval/varをつけるとそのフィールドは公開され、外部からアクセスできるようになります
        * `+` ってなんだ？ → メソッド定義へ

## メソッド定義

* 一般型

    ```scala
    (private[this/package名]/protected[package名]) def methodName(parameter1: Type1, parameter2: Type2, ...): ReturnType = {
      ???
    }
    ```

* メソッド本体が1つの式だけからなる場合

    ```scala
    (private[this/package名]/protected[package名]) def methodName(parameter1: Type1, parameter2: Type2, ...): ReturnType = ???
    ```

* 実際に使ってみる

    ```scala
    scala> class Point(val x: Int, val y: Int) {
         |   def +(p: Point): Point = {
         |     new Point(x + p.x, y + p.y)
         |   }
         |   override def toString(): String = "(" + x + ", " + y + ")"
         | }
    defined class Point


    scala> val p1 = new Point(1, 2)
    p1: Point = (1, 2)

    scala> val p2 = new Point(4, 8)
    p2: Point = (4, 8)


    scala> println(p1.x.toString + " " + p1.y.toString)
    1 2

    scala> println(p2.x.toString + " " + p2.y.toString)
    4 8


    scala> val p3 = p1 + p2
    p3: Point = (5, 10)
    ```
    * `val p3 = p1 + p2` を使用するための `+` だったのか

* 一応確かめで `+` を定義しなかった場合の処理

    ```scala
    scala> class Point(val x: Int, val y: Int) {
         |   override def toString(): String = "(" + x + ", " + y + ")"
         | }
    defined class Point

    scala> val p1 = new Point(1, 2)
    p1: Point = (1, 2)

    scala> val p2 = new Point(4, 8)
    p2: Point = (4, 8)

    scala> val p3 = p1 + p2
    <console>:10: error: type mismatch;
     found   : Point
     required: String
           val p3 = p1 + p2
    ```

## 複数の引数リストを持つメソッド

* 一般型

    ```scala
    def methodName(parameter11: Type11, parameter12: Type12, ...)(...)(parameterN1: TypeN1, ..., parameterNM: TypeNM): RerurnType = ???
    ```

* 使い方

    ```scala
    scala> class Adder { def add(x: Int)(y: Int): Int =  x + y  }
    defined class Adder

    scala> val adder = new Adder()
    adder: Adder = Adder@3acc82b0

    scala> val result = adder.add(1)(2)
    result: Int = 3

    scala> val func = adder.add(10)_
    func: Int => Int = <function1>

    scala> func(20)
    res11: Int = 30
    ```
    * `val func = adder.add(10)_` 最初の引数だけを適用して新しい関数を作る（部分適用）こともできる
    * 部分適用で共通処理の簡略化ができそう

## フィールド定義

* 一般型

    ```scala
    (private[this/package名]/protected[package名]) (val/var) fieldName: Type = Expression
    ```
    * `private` / `protected` 関連
        * `private` ：そのクラス内のみでアクセス可能
        * `protected` ：そのクラスの派生クラスからのみアクセス可能
        * `private[this]` ：同一オブジェクトからのみアクセス可能
            * 一般にJVMレベルでのフィールドへの直接アクセスになるため、若干高速
        * `private/protected[package名]`：同一パッケージからの各定義でのアクセス可能