Kotlin文法 - 分解宣言、範囲、型チェックとキャスト


# はじめに

[Kotlin文法 - 関数とラムダ](http://qiita.com/k5n/items/964d765767a65cc3de5b)の続き。

[Kotlin Reference](https://kotlinlang.org/dscs/reference/)のOther章Destructuring Declarations, Ranges, Type Checks and Castsの大雑把日本語訳。適宜説明を変えたり端折ったり補足したりしている。

# 分解宣言

オブジェクトを幾つかの変数に分解できたら便利なことがあるよね。こんな風に。

```kotlin
// personの中身をname, ageにバラして代入
val (name, age) = person

// 個別に使える
println(name)
println(age)
```

この記法は *分解宣言(destructuring declaration)* とよばれている。分解宣言では一度に複数の変数が宣言できる。

分解宣言は以下のコードにコンパイルされる。

```kotlin
val name = person.component1()
val age = person.component2()
```

もちろんcomponent3(), component4()と続けることができる。これらのcomponentN()関数は *operator* キーワードを付けて宣言しておく必要がある。

分解宣言は *for* ループでも使える。

```kotlin
for ((a, b) in collection) { ... }
```

## 例: 関数から２つの値を返す

関数から２つの値を返す必要がある場合を考えよう。例えば結果と何らかのステータスを返す場合。Kotlinでこれをやるには、データクラスを宣言してそのインスタンスを結果として返す方法が使える。

```kotlin
// ２つの値をもつデータクラス
data class Result(val result: Int, val status: Status)

fun function(...): Result {
    // 計算
    
    // データクラスを使って２つの値を返す
    return Result(result, status)
}

// 関数を使って、結果から２つの値を取り出す
val (result, status) = function(...)
```

データクラスは自動的にcomponentN()関数を作ってくれるので、分解宣言が機能する。

注：標準で用意されている *Pair* も使えるけど、ちゃんと名前の付いたプロパティを持つデータを使ったほうがいいよ。

## 例: マップと分解宣言

たぶんマップを横断するのにこんな風にできたらいいよね。

```kotlin
for ((key, value) in map) {
   // do something with the key and the value
}
```

これをやるには、以下であるべき。

 - *iterator()* を提供することで値の列としてマップを表現する
 - *component1()*, *component2()* を提供することでペアとして各要素を表現する

で実際、標準ライブラリはこんな拡張を提供してる。

```kotlin
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
```

なのでマップを *for* ループするのに自由に分解宣言を利用できる（データクラスインスタンスのコレクションと同様に）。

# 範囲

範囲式は *..* 演算子を使って表し、*in*, *!in* と一緒に使える。*範囲* は比較可能な型に定義されているが、整数のプリミティブ型に対しては最適化された実装を持つ。

※演算子オーバーロードの項で説明するが、*a .. b* 演算子は *a.rangeTo(b)* メソッド呼び出しに変換される。また *a in b* は *a.contains(b)*, *a !in b* は *!a.contains(b)* に変換される。


```kotlin
if (i in 1..10) { // 1 <= i && i <= 10 と等価
  println(i)
}
```

整数型の *範囲(IntRange, LongRange, CharRange)* は特別な機能を持っており、これらはイテレート可能。コンパイラは特別なオーバーヘッドなしにJavaの *for* 文のインデックスのように扱う。

```kotlin
for (i in 1..4) print(i) // "1234"と表示される

for (i in 4..1) print(i) // 何も表示されない
```

逆順に回したい時はどうするかって？標準ライブラリにある *downTo()* 関数が使える。

```kotlin
for (i in 4 downTo 1) print(i) // "4321"と表示される
```

ステップを自由に決めるにはどうするのかって？*step()* 関数を使う。

```kotlin
for (i in 1..4 step 2) print(i) // "13"と表示される

for (i in 4 downTo 1 step 2) print(i) // "42"と表示される
```

## どうやって動いているのか

*範囲* はライブラリ内の共通インターフェース *ClosedRange&lt;T&gt;* を実装している。

*ClosedRange&lt;T&gt;* は比較可能な型に定義されている数学で言う所の閉区間を表している。そして範囲内に含まれる *start* と *encInclusive* の２つの端点を持つ。主要演算の *contains* は通常 *in*, *!in* 演算子の形で利用される。

整数型の *IntProgression*,  *LongProgression*, *CharProgression* は数学で言う数列を表す。これは *first*, *last*, そしてゼロでない *increment* を要素に持つ。最初の要素が *first*  で、続く要素は前の要素に *increment* 足したものになる。たとえ数列が空であっても *last* は必ずイテレーションでヒットする。

数列は *Iterable&lt;N&gt;* のサブ型であり、ここで *N* は *Int*, *Long*, *Char* である。なので *for* ループや *map* や *filter* といった関数で使うことができる。数列に対するイテレーションはJavaやJavascriptのインデックス付き *for* ループと等価である。

```kotlin
for (int i = first; i != last; i += increment) {
  // ...
}
```

整数型において *..* 演算子は *ClosedRange&lt;T&gt;* と *○○Progression* を実装したオブジェクトを生成する。例えば *IntRange* は *ClosedRange&lt;Int&gt;* を実装し、*IntProgression* を継承する。なので *IntProgression* に定義されている全ての演算子は *IntRange* でも同様に有効。*downTo()*, *step()* 関数の結果は常に *○○Progression* である。

数列はコンパニオンオブジェクトに定義されている *fromClosedRange()* 関数で構築される。

```kotlin
  IntProgression.fromClosedRange(start, end, increment)
```

数列の *last* 要素は、*increment* が正なら *end* 以下で最大の、*increment* が負なら *end* 以上で最小の *(last - first) % increment == 0* である値が計算される[^1]。

[^1]: これ本当？for (i in 4..1)ではループは実行されないという。first=4, end=1, increment=1なので、lastは1になる。・・・上のインデックス付きループと等価だったらループしまくってiがオーバーフローするじゃん。空の場合はlastはfirstと同じ値が入るルールがある？

## 便利関数

### rangeTo()

整数型の *rangeTo()* 演算子は単純に *○○Range* のコンストラクタを呼ぶ。

```kotlin
class Int {
  //...
  operator fun rangeTo(other: Long): LongRange = LongRange(this, other)
  //...
  operator fun rangeTo(other: Int): IntRange = IntRange(this, other)
  //...
}
```

浮動小数点数( *Double*, *Float* )には *rangeTo* は定義されていない。標準ライブラリがジェネリックな *Comparable* 型のために用意しているものを代わりに使う。

```kotlin
  public operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
```

この関数が返す *ClosedRange* はイテレーションには利用できない。

### downTo()

*downTo()* 拡張関数は整数型のそれぞれのペアに用意されている。以下はそのうち２つの例。

```kotlin
fun Long.downTo(other: Int): LongProgression {
  return LongProgression.fromClosedRange(this, other, -1.0)
}

fun Byte.downTo(other: Int): IntProgression {
  return IntProgression.fromClosedRange(this, other, -1)
}
```

### reversed()

*reversed()* 拡張関数はそれぞれの *○○Progression* クラスに定義されている。これらは逆順の数列を返す。

```kotlin
fun IntProgression.reversed(): IntProgression {
  return IntProgression.fromClosedRange(last, first, -increment)
}
```

### step()

*step()* 拡張関数はそれぞれの *○○Progression* クラスに定義されている。これはステップ量を変更した数列を返す。ステップ量は常に正でなければならず、この関数は数列の方向を変更しない。

```kotlin
fun IntProgression.step(step: Int): IntProgression {
  if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step")
  return IntProgression.fromClosedRange(first, last, if (increment > 0) step else -step)
}

fun CharProgression.step(step: Int): CharProgression {
  if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step")
  return CharProgression.fromClosedRange(first, last, step)
}
```

*last* が元の数列と異なること場合があることに注意。(last - first) % increment == 0 を満たさなければならないため。例えば以下のように。

```kotlin
  (1..12 step 2).last == 11  // 次の値からなる数列 [1, 3, 5, 7, 9, 11]
  (1..12 step 3).last == 10  // 次の値からなる数列 [1, 4, 7, 10]
  (1..12 step 4).last == 9   // 次の値からなる数列 [1, 5, 9]
```

# 型チェックとキャスト

## is と !is 演算子

実行時にオブジェクトがある型の一種であるかどうか[^2]を判定するのに *is* が、その否定に *!is* が利用できる。

[^2]: Javaのinstanceofと同じ

```kotlin
if (obj is String) {
  print(obj.length)
}

if (obj !is String) { // !(obj is String) と同じ
  print("Not a String")
}
else {
  print(obj.length)
}
```

## スマートキャスト

多くの場合Kotlinでは明示的なキャストは必要ない。コンパイラが不変な値への *is* チェックを行ったことを追跡して、必要であれば自動的にキャストを（安全に）挿入してくれる。

```kotlin
fun demo(x: Any) {
  if (x is String) {  // ここでxがStringがどうかチェックしたので
    print(x.length)   // ここではxは自動的にStringにキャストされている
  }
}
```

また || や && の右側で、

```kotlin
  // `||`の右側ではxは自動的にStringにキャストされている
  if (x !is String || x.length == 0) return

  //`&&`の右側では x は自動的にStringにキャストされている
  if (x is String && x.length > 0)
      print(x.length) // xは自動的にStringにキャストされている
```

チェックと利用との間で変数が変更されないことをコンパイラが保証できない時は、スマートキャストが効かないことに注意。もっと仕様っぽい書き方をすると、次のルールに沿って有効になる。

 - *val* なローカル変数 - 常に。
 - *val* なプロパティ - プロパティが *private* か *internal* かプロパティが宣言されたのと同じモジュール内でチェックが実行される場合。*open* なプロパティやカスタムgetterを持つプロパティでは有効にならない。
 - *var* なローカル変数 - チェックと利用の間で値が変更されず、それを変更するようなラムダにキャプチャされない場合。
 - *var* なプロパティ - 決して有効にならない（コード内でいつでも変更可能なので）。

## 「安全でない」キャスト演算子

通常キャスト演算子はキャストに失敗すると例外を投げる。なので「安全でない」と言っている。Kotlinでの安全でないキャストは *as* 接中辞演算子で行われる。

```kotlin
val x: String = y as String
```

*null* は *String* にキャストできないことに注意。*Nullable* でないので。つまりもし *y* が *null* なら上のコードは例外を投げる。Javaでのキャストと同じようにするには、右側に *Nullable* 型を用いる。こんな風に。

```kotlin
val x: String? = y as String?
```

## 「安全な」(nullable)キャスト演算子

例外が投げられるのを避けたければ、安全なキャスト演算子 *as?* が使える。これは失敗すると *null* を返す。

```kotlin
val x: String? = y as? String
```

*as?* の右側が *Nullbale* でない *String* であっても、キャストの結果は *Nullable* になることに注意。

# 次の章へ

次は[Kotlin文法 - this、等価性、演算子オーバーロード、Null安全、例外](http://qiita.com/k5n/items/6fe586bf2e5530684681)へGO!