Scalaの制御構文(2)

# はじめに

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

# Scalaの制御構文
http://qiita.com/tamagokake_gohan/items/ee2ce1157c5f4e646a66
の続き

ざっくりまとめ

* match式はbreakが無い代わりに `|` によって複数のOR条件をつけることが可能
* match式は型の識別ができるがObjectであることや、JVMの制約等があるため使用するときは注意が必要

## match式
* 一般系

    ```scala
    マッチ対象の式 match {
        case パターン1 [if ガード1] => 式1
        case パターン2 [if ガード2] => 式2
        case パターン3 [if ガード3] => 式3
        case ...
        case パターンN => 式N
    }
    ```
* 使用方法
    * 通常使用

        ```scala
        scala> val name: String = "taro"
        name: String = taro

        scala> name match {
             |     case "taro" => "Male"
             |     case "Jiro" => "Male"
             |     case "Hanako" => "Female"
             | }
        res18: String = Male
        ```
    * ワイルドカード

        ```scala
        scala> val number1: Int = 1
        number1: Int = 1

        scala> val number2: Int = 2
        number2: Int = 2

        scala> val number3: Int = 3
        number3: Int = 3

        scala> number1 match { case 1 => "one"; case 2 => "two"; case _ => "other"}
        res22: String = one

        scala> number2 match { case 1 => "one"; case 2 => "two"; case _ => "other"}
        res23: String = two

        scala> number3 match { case 1 => "one"; case 2 => "two"; case _ => "other"}
        res24: String = other
        ```
    * 型が違う場合

        ```scala
        scala> val number1: Integer = 1
        number1: Integer = 1


        scala> number1 match { case 1 => "one"; case 2 => "two"; case _ => "other"}
        <console>:9: error: type mismatch;
         found   : Int(1)
         required: Integer
                      number1 match { case 1 => "one"; case 2 => "two"; case _ => "other"}
                                           ^
        ```
        * errorとして返されるから注意が必要
    * C言語だとbreakがあるが、Scalaだと無いのでまとめる

        ```scala
        scala> val str: String = "a"
        str: String = a

        scala> str match { case "a" => "A"; case "b" => "B"; }
        res25: String = A

        scala> str match { case "a" | "b" => "A or B"}
        res26: String = A or B
        ```
    * パターンマッチで値を取り出す

        ```scala
        scala> val lst = List("A", "B", "C")
        lst: List[String] = List(A, B, C)

        scala> lst match { case List("A", b, c) => "A" + b + c; case _ => "other"}
        res27: String = ABC

        scala> lst match { case List(a, "B", c) => a + "B" + c; case _ => "other"}
        res28: String = ABC

        scala> lst match { case List("A", b, c) if b != "B" =>  "A" + b + c; case _ => "other"}
        res29: String = other
        ```
        * case文内でif処理を同時にできるのは便利
        * Listの途中であっても、判定可能（どこでも良いみたい）
    * ネストしている場合の取得

        ``` scala
        scala> val lst = List(List("N"), List("A", "B", "C"))
        lst: List[List[String]] = List(List(N), List(A, B, C))

        scala> lst match { case List(n@List("N"), x) => n + x; case _ => "other"}
        <console>:9: error: type mismatch;
         found   : List[String]
         required: String
                      lst match { case List(n@List("N"), x) => n + x; case _ => "other"}
                                                                   ^

        scala> lst match { case List(n@List("N"), x) => print(n) + print(x); case _ => "other"}
        <console>:9: error: type mismatch;
         found   : Unit
         required: String
                      lst match { case List(n@List("N"), x) => print(n) + print(x); case _ => "other"}
                                                                               ^

        scala> lst match { case List(n@List("N"), x) => print(n) ; print(x); case _ => "other"}
        List(N)List(A, B, C)res32: Any = ()
        ```
        * 検索対象は `@` で取り出すことが可能
        * `;;` はちょっと気持ちが悪い（というより通常一行で書かないか・・・）
        * ついでに `print` の返り値はUnit型なのでString型の結合はできない
    * `|` を使ったパターンマッチの場合は値を取り出すことができない

        ```scala
        scala> (List("a"): Any) match { case List(a) | Some(a) => println(a)}
        <console>:8: error: illegal variable in pattern alternative
                      (List("a"): Any) match { case List(a) | Some(a) => println(a)}
                                                         ^
        <console>:8: error: illegal variable in pattern alternative
                      (List("a"): Any) match { case List(a) | Some(a) => println(a)}
                                                                   ^

        scala> val str: String = "a"
        str: String = a

        scala> str match { case a@"a" | a@"b" => a}
        <console>:9: error: illegal variable in pattern alternative
                      str match { case a@"a" | a@"b" => a}
                                       ^
        <console>:9: error: illegal variable in pattern alternative
                      str match { case a@"a" | a@"b" => a}
                                               ^
        ```
        * 組み合わせの場合取り出せないのは不便？
            * そもそもそんな書き方をするのがナンセンスってことで弾かれていそう
    * 型によるパターンマッチ

        ```scala
        scala> val target_s: String  = "hoge"
        target_s: String = hoge

        scala> target_s match { case String => "is string"; case Integer => "is Integer"; case _ => "other"}
        <console>:9: error: object java.lang.String is not a value
                      target_s match { case String => "is string"; case Integer => "is Integer"; case _ => "other"}
                                            ^
        <console>:9: error: object java.lang.Integer is not a value
                      target_s match { case String => "is string"; case Integer => "is Integer"; case _ => "other"}
        ```
        * matchのcaseに対して型を直接入れることはできないっぽい
            * 値じゃねーよって怒れる。まぁ、そうかｗ

        ```scala
        scala> val target_s: String  = "hoge"
        target_s: String = hoge

        scala> target_s match { case v:String => "is string"; case v:Integer => "is Integer"; case _ => "other"}
        <console>:9: error: scrutinee is incompatible with pattern type;
         found   : Integer
         required: String
                      target_s match { case v:String => "is string"; case v:Integer => "is Integer"; case _ => "other"}
                                                                            ^
        ```
        * 対象の式に対して型が違うと怒られる
            * Object型の式でないからかな？

        ```scala
        scala> val target_s: AnyRef  = "hoge"
        target_s: AnyRef = hoge

        scala> target_s match { case v:String => "is string"; case v:Integer => "is Integer"; case _ => "other"}
        res44: String = is string
        ```
        * Object型ならマッチする

        ```scala
        scala> val target_s: AnyRef  = "hoge"
        target_s: AnyRef = hoge

        scala> target_s match { case String => "is string"; case Integer => "is Integer"; case _ => "other"}
        <console>:9: error: object java.lang.String is not a value
                      target_s match { case String => "is string"; case Integer => "is Integer"; case _ => "other"}
                                            ^
        <console>:9: error: object java.lang.Integer is not a value
                      target_s match { case String => "is string"; case Integer => "is Integer"; case _ => "other"}
                                                                        ^
        ```
        * ちなみに、対象の式がObject型であっても、パターンに対して変数を仕込む必要がある

        ```scala
        scala> val target_s: AnyRef  = "hoge"
        target_s: AnyRef = hoge

        scala> target_s match { case v:String => v + " is string"; case v:Integer => v + " is Integer"; case _ => "other"}
        res47: String = hoge is string
        ```
        * match内部で変数を使用することが可能

        ```scala
        scala> val target_s: AnyRef  = "hoge"
        target_s: AnyRef = hoge

        scala> target_s match { case v@String => v + " is string"; case v@Integer => v + " is Integer"; case _ => "other"}
        <console>:9: error: object java.lang.String is not a value
                      target_s match { case v@String => v + " is string"; case v@Integer => v + " is Integer"; case _ => "other"}
                                              ^
        <console>:9: error: object java.lang.Integer is not a value
                      target_s match { case v@String => v + " is string"; case v@Integer => v + " is Integer"; case _ => "other"}
                                                                                 ^

        scala> target_s match { case c@v:String => v + " is string"; case c@v:Integer => v + " is Integer"; case _ => "other"}
        <console>:1: error: '=>' expected but ':' found.
               target_s match { case c@v:String => v + " is string"; case c@v:Integer => v + " is Integer"; case _ => "other"}
                                        ^
        <console>:1: error: '=>' expected but ':' found.
               target_s match { case c@v:String => v + " is string"; case c@v:Integer => v + " is Integer"; case _ => "other"}
                                                                             ^
        ```
        * 遊び心で `@` や `:` を組み合わせて見たが、エラーですねｗ
    * JVMの制約による型のパターンマッチの落とし穴

        ```scala
        scala> val obj: Any = List("a")
        obj: Any = List(a)

        scala> obj match {
             |     case v: List[Int]    => println("List[Int]")
             |     case v: List[String] => println("List[String]")
             | }
        <console>:10: warning: non-variable type argument Int in type pattern List[Int] is unchecked since it is eliminated by erasure
                          case v: List[Int]    => println("List[Int]")
                                  ^
        <console>:11: warning: non-variable type argument String in type pattern List[String] is unchecked since it is eliminated by erasure
                          case v: List[String] => println("List[String]")
                                  ^
        <console>:11: warning: unreachable code
                          case v: List[String] => println("List[String]")
                                                         ^
        List[Int]
        ```
        * 型変数を使った場合、正しくパターンマッチが実施されない
            * 型変数を含む型のパターンマッチは、ワイルドカードパターンを使うとよいとのこと
            
            ```scala
            obj match {
              case v: List[_] => println("List[_]")
            }
            ```