条件式とループ
if式
Kotlinでは、ifは式であり、すなわち値を返します。従って、三項演算子は存在しません(条件 ? 真の時 : 偽の時
)。なぜなら普通の if がその役割を果たすためです。
if の分岐はブロックにすることができ、最後の式がそのブロックの値となります:
val max = if (a > b) {
print("aを選びます")
a
} else {
print("bを選びます")
b
}
もしifを文ではなく式として使用する(例えば値を返したり変数に代入したりする)ならば、その式にはelse
分岐が必要です。
when式
when は一つの条件式に複数の分岐を定義します。 C系の言語におけるswitch式に似ています。最も簡単な形式では、次のようになります:
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x は1でも2でもありません")
}
}
when はその引数が満たされる分岐が現れるまで、順番に全ての分岐に対して比較されます。
when は式としても文としても使うことができます。 もし式として使用されれば、その値は条件が最初に満たされた分岐の値が式全体の値となります。 もし文として使用されれば、個別の分岐の値は無視されます。 ifと同様に各分岐はブロックでも良く、その場合は値はブロック内の最後の式のものとなります。
else節は他の分岐の条件が全て満たされなかった際に評価されます。
もしwhen
が式として使用されれば、全てのあり得る場合を分岐条件で網羅できていることをコンパイラが保証出来ない限りは、else節は必須です。
全部の分岐条件を網羅出来ている事をコンパイラが保証出来るケースとしては、
列挙型クラスのエントリやsealed
クラスのサブタイプなどが挙げられます。
enum class Bit {
ZERO, ONE
}
val numericValue = when (getRandomBit()) {
Bit.ZERO -> 0
Bit.ONE -> 1
// 全部のケースをカバー出来ているので 'else' は不要
}
when
文では、以下のケースでは else
節は必須です:
when
の条件がBoolean
、enum
、sealed
型か、そのnullableバージョンの場合(訳注:この文は誤りな気がする、たぶんBooleanの場合だけが正解)when
の分岐が対象のすべてのケースをカバーしていない場合
enum class Color {
RED, GREEN, BLUE
}
when (getColor()) {
Color.RED -> println("red")
Color.GREEN -> println("green")
Color.BLUE -> println("blue")
// 全部のケースがカバーされているので 'else' は不要
}
when (getColor()) {
Color.RED -> println("red") // GREENとBLUEについての分岐が無い
else -> println("not red") // 'else' が必要
}
複数のケースに対して共通の処理をしたい場合は、分岐の条件を一行でカンマでまとめる事が出来ます:
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("それ以外")
}
分岐条件として任意の式(定数に限らない)を使用することができます:
when (x) {
parseInt(s) -> print("sはxをエンコードする")
else -> print("sはxをエンコードしない")
}
inまたは!inを使用すると、コレクションや 範囲 (range) に入っているかをチェックすることもできます:
when (x) {
in 1..10 -> print("xは範囲内")
in validNumbers -> print("xは有効")
!in 10..20 -> print("xは範囲外")
else -> print("どれにも該当せず")
}
値をチェックする他の方法として、特定の型のisまたは!isがあります。 スマートキャストのおかげで、その型のメソッドやプロパティに追加のチェック無しでアクセスできることに注意してください。
val hasPrefix = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
whenは if-else if連鎖を代替することもできます。 引数が与えられない場合は、分岐条件は単純なbooleanの式となり、分岐はその条件がtrueの場合に実行されます:
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
以下のシンタックスを使って、whenの対象を変数に捕捉する事が出来ます。
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
whenの対象の所で導入された変数のスコープは、whenの本体の中のみです。
Forループ
forループはイテレータによって提供されるものを何でも繰り返し実行します。
これはC#などの言語のforeach
と同等です。
for
の構文は次のとおりです:
for (item in collection) print(item)
for
の本文をブロックにすることもできます。
for (item: Int in ints) {
// ...
}
前述したように、 for はイテレータを提供するものを何でも繰り返し実行します。すなわち:
- メンバ関数や拡張関数の
iterator()
でIterator<>
型をすもの:- メンバ関数や拡張関数の
next()
を持つ - メンバ関数や拡張関数で
Boolean
を返すhasNext()
を持つ
- メンバ関数や拡張関数の
これら3つの関数は全て operator
としてマークされる必要があります。(訳注:operatorキーワードを指定する必要がある)
数字の範囲を繰り返し実行したい場合は、range式 が使えます:
rangeや配列のfor
ループはインデックスベースのループにコンパイルされ、
イテレータオブジェクトを作成しません。
もし配列やリストをインデックス付きで繰り返し処理したいならば、以下の方法を使用できる:
別方法として、ライブラリ関数の withIndex を使用することもできます:
whileループ
while
とdo-while
ループは与えられた条件が満たされている間、本体を実行し続けます。
両者の違いは条件を確認するタイミングです:
while
は条件をチェックし、それが満たされていたら、本体を実行してまた条件チェックに戻りますdo-while
は本体を実行し、それから条件をチェックします。もし条件が満たされていたら、ループをもう一度実行します。つまり、do-while
の本体は条件によらず最低でも一回は実行されます。
while (x > 0) {
x--
}
do {
val y = retrieveData()
} while (y != null) // y はここで可視(visible)
ループ内でのbreakとcontinue
Kotlinは従来通りの、ループ内の breakとcontinue 演算子をサポートしています。Returnとジャンプを参照してください。