第7章：タプルにチャレンジ！

第7章も相変わらず __型__ について語るぞ！
今回の主役は、Javaプログラマーには馴染みがない __タプル__ ！

# 複数の戻り値
戻り値で複数の異なる型を返したくなったことはある？
Javaだと引数の型は1つと決まっているから、単純には実現できないよね。
だから、代替案としてこんな手を使ったりするよね。

- 例えば、新たなDTO等の __情報格納役__ を定義し、そのフィールドに複数の型を用意する
- 引数に複数のオブジェクトを渡して、戻り値相当をそのオブジェクトに設定する
- インタフェースを分割する。つまりそれぞれのデータを返すメソッドを用意する
- 戻り値をコレクションにして、複数の型のオブジェクトを格納する(ほとんどやらないけど)

どれも面倒臭いんだよね。クラス名決めるのだって大変だし。。。

Javaの世界では諦めモードだけど、Scalaの世界では素晴らしい仕組みが備わっているんだ。
複数の型を返す仕組み、 __タプル__ だ！

# タプルの例

早速ソースを見てみよう。

```scala:Tuple.scala
object Tuple {

  def getMaxValue(numbers: List[Int]) = {
    val max = numbers.max
    val index = numbers.indexOf(max)
    (max, index)
  }

  def main(args: Array[String]){
    val numbers = List(1, 2, 3, 4, 5, 10, 6)

    val maxValue = getMaxValue(numbers)
    printf("max=%s \n", maxValue._1)
    printf("index=%s \n", maxValue._2)
  }

}
```
## 実行
実行すると以下のようになるよ。

    $ scalac Tuple.scala
    
    $ scala Tuple
    max=10
    index=5

## ソースの説明
Tuple.scalaは単純なソースだ。
引数に`Int`の`List`を受け取り、以下の戻り値を返すメソッド`getMaxValue`を定義する。

- 引数の`List`の __最大値__
- 引数の`List`の __最大値のインデックス__

そして、その戻り値を確認する。

この説明だけで、メソッド`getMaxValue`内でどれがタプルかわかるだろ？
`(max, index)`がタプルだ。

    val max = numbers.max
    val index = numbers.indexOf(max)

`List`の最大値と最大値のインデックスはここで取得しているんだ。

    val maxValue = getMaxValue(numbers)
    printf("max=%s \n", maxValue._1)
    printf("index=%s \n", maxValue._2)

タプルを変数`maxValue`に格納して、`_1` `_2`でそれぞれの要素にアクセスしている。
格納した順番通りなので

- `_1`が最大値
- `_2`が最大値のインデックス

となる。

# タプルとは
タプルとは、 __複数の異なる型__ を格納できるコンテナオブジェクトだ。
つまり __情報格納役__ になる。

もちろんタプルにも型が存在している。
`scala.TupleN`として、1～22のNに対してTupleNクラスが定義されている(ようだ)。
ということは、タプルには22個まで要素を格納できる。

また、それぞれの要素にアクセスするには`_N`とする。

# タプルの限界

22個なんて使うことはないと思いつつ、22個を超過したらどうなるか試してみる。

## Tuple22
22個は最大値なので問題ないはず。

```scala:Tuple22.scala
object Tuple22 {

  def get() = {
    (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)
  }

  def main(args: Array[String]){
    val tuple = get()
    printf("element_1=%s \n", tuple._1)
    printf("element_22=%s \n", tuple._22)
  }

}
```
22個の要素を持つタプルを用意して、1要素目と22要素目を取得する。

### 実行
    $ scalac Tuple22.scala

    $ scala Tuple22
    element_1=1
    element_22=22

これは期待通りの動きとなった。

## Tuple23
23個の要素を持つタプルは、型が存在しないので`scalac`でエラーになるはず。

```scala:Tuple23.scala
object Tuple23 {

  def get() = {
    (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23)
  }

  def main(args: Array[String]){
    val tuple = get()
    printf("element_1=%s \n", tuple._1)
    printf("element_23=%s \n", tuple._23)
  }

}
```

### 実行
`scalac`してみると

    $ scalac Tuple23.scala
    Tuple23.scala:4: error: object Tuple23 is not a member of package scala
          (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23)
          ^
    one error found

`Tuple23`なんていないぜって言っているから、予想通りだ。
23個以上は使うなよ！

## Function22
`Function22`というのもあるんだ。
引数の数に応じて、`Function1`～`Function22`まで存在している。
つまり23個以上は使えないってこと？

```scala:Func22.scala
object Func22 {
  def main(args: Array[String]) {
    val func22 : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = null;
  }
}
```

### 実行
`scalac`してみるよ！

    scalac Func22.scala
    

コンパイルエラーはでないね。


## Function23
次は`Function23`を見てみよう。

```scala:Func23.scala
object Func23 {
  def main(args: Array[String]) {
    val func23 : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = null;
  }
}
```

### 実行
`scalac`してみるよ！

    $ scalac Func23.scala
    Func23.scala:3: error: type Function23 is not a member of package scala
        val func23 : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = null;
                                                     ^
    one error found

今度はコンパイルエラーになったね。`Function23`なんて型はないぜ！って言っている。
関数の引数は、やっぱり22個までということですね。

# 情報格納役オブジェクトで試す
`Int`の場合で試してみたので、今度は情報格納役オブジェクト
所謂JavaBean的なオブジェクトで試してみよう！

振る舞いも入れてみてるからな。

```scala:CaseClassTuple.scala
object CaseClassTuple {

  def get() = {
    val name = new Name("清美", "椿山")
    (Human(name, 15), name)
  }

  def main(args: Array[String]){
    val tuple = get()
    printf("fullname_1=%s \n", tuple._1.name.fullname)
    printf("fullname_2=%s \n", tuple._2.fullname)
  }

}

class Name(first: String, last: String) {
  def fullname() = first + " " + last
}

case class Human(name: Name, age: Int)
```

## 実行
実行してみる。

    $ scalac CaseClassTuple.scala

    $ scala CaseClassTuple
    fullname_1=清美 椿山
    fullname_2=清美 椿山

これもウマくいった。
ほぼほぼどんなオブジェクトでもいけそうな予感。

# タプルもイミュータブル
もちろんというか、タプルもイミュータブルなので要素の入れ替えができないよ。
ちょっとチャレンジしてみました。

```scala:TupleImmutable.scala
object TupleImmutable {

  def get(x1: Int, x2: Int) = {
    (x1, x2)
  }

  def main(args: Array[String]){
    val tuple = get(1, 2)
    tuple._1 = 3
  }

}
```

## 実行
`scalac`してみる。

    $ scalac TupleImmutable.scala
    TupleImmutable.scala:9: error: reassignment to val
    tuple._1 = 3
             ^
    one error found

__イミュータブルだぜ！アサインできないぞ！__と言っているね！

# タプルのメリット
型の増大を防ぐことができるのがメリットだと思うよ。
特に、サービス層で使える気がしている。

異なる型のデータ取得のためだけに、サービスのインタフェースを複数切っていたところを、
Facadeにまとめてしまい、タプルでデータを返すってコトができると思う。

他にも使い道ありそうだね。

# まとめ
今回はタプルについて語ってみたけどどうかな？
自分が疑問に思っていたところも試すことが出来たから、良かったぞ。

今回も
__体で感じてくれたかな？__