ジャンプとは
ジャンプとは、分岐や繰り返しなどの制御フローの途中に挿入することで、
関数やループを途中で抜けたり、あるいは特定の条件のときにループをスキップしたりすることができます。
Kotlinには制御をジャンプするために、次の式が用意されています。
式 | 説明 |
---|---|
return | デフォルトでは、returnを含む最も内側の関数、匿名関数から制御を返す |
break | そのbreakを含む最も内側のループを終了する |
continue | そのcontinueを含む最も内側のループに対して、そのループをスキップして次のループにすすめる |
fun main(args: Array) {
// ブレーク、コンティニューの条件をラムダ式で指定する
val isBreak = { i: String -> i == "BreakStr" }
val isContinue = { i: String -> i == "ContinueStr"}
testLoop(null, isBreak, isContinue)
testLoop(listOf("suzuki", "tanaka", "BreakStr", "yamada"), isBreak, isContinue)
testLoop(listOf("suzuki", "tanaka", "ContinueStr", "yamada"), isBreak, isContinue)
}
fun testLoop(list: List?, isBreak: (String) -> Boolean, isContinue: (String) -> Boolean) {
println("-------------------")
if (list == null) {
// listがnullの場合はこの関数を抜ける
println("Return!")
return
}
for (i in list) {
if (isBreak(i)) {
// ブレーク条件をみたす場合は、ループを終了する
println("Break!")
break
}
if (isContinue(i)) {
// コンティニュー条件を満たす場合は、今回分の処理をスキップして、次の分の処理に進む
println("Continue!")
continue
}
println(i)
}
}
-------------------
Return!
-------------------
suzuki
tanaka
Break!
-------------------
suzuki
tanaka
Continue!
yamada
ラベル付きbreak/continue
ループにラベルをつけることで、breakやcontimueで特定のラベルのループを抜けることができます。
ラベルは@とラベル名で指定します。
これは、多重にネストしたループを一気に抜けたりする場合に便利です
fun main(args: Array) {
val data = listOf(1, 2, 3,
4, 5, 6,
7, 0, 8,
9, 10, 11,
12, -1, 13,
14, 15, 16)
labelLoop(data, 3, 6)
}
fun labelLoop(data: List, width: Int, height: Int) {
if (data.size != width * height) return
outerLoop@ for (y in 0 until height) {
for (x in 0 until width) {
val d = data[x + y * width]
if (d < 0) break@outerLoop
if (d == 0) {
print("\n")
continue@outerLoop
}
print("${d} ")
}
print("\n")
}
}
1 2 3
4 5 6
7
9 10 11
12
ラベル付きreturn
Kotlinでは、関数はネスト可能です。
通常のreturnは、そのreturnを囲む一番内側の(匿名)関数をリターンします。
次の例を見てみましょう。
fun main(args: Array) {
outerFunc()
}
fun outerFunc() {
println("Called outerFunc")
fun innerFunc(value: Int) {
println(" Called innerFunc")
if (value < 0) {
println(" Return innerFunc")
// このリターンはinnerFuncを終了する
// outerFuncは終了しない
return
}
println(" End of innerFunc")
}
innerFunc(10)
innerFunc(-5)
println("End of outerFunc")
}
この、そのreturnを囲むというのが特に重要な意味を持つのは、
ラムダ式の中にreturnがある場合です。
次のサンプルの動作を確認してみましょう。
fun main(args: Array) {
outerFunc(listOf("suzuki", "yamada", "ReturnStr", "tanaka"))
}
fun outerFunc(list: List) {
println("Called outerFunc")
val outerVal = "outerFuncで宣言された変数"
list.also {
println("ラムら式はクロージャなので、${outerVal}にアクセスできる。")
}.forEach {
// このreturnは、outerFuncを直接リターンする
if (it == "ReturnStr") return
println(it)
}
println("End of outerFunc")
}
Called outerFunc
ラムら式はクロージャなので、outerFuncで宣言された変数にアクセスできる。
suzuki
yamada
もし、ラムダ式の中のreturnでラムダ式をリターンしたい場合は、ラベルを付ける必要があります。
fun main(args: Array) {
outerFunc(listOf("suzuki", "yamada", "ReturnStr", "tanaka"))
}
fun outerFunc(list: List) {
println("Called outerFunc")
val outerVal = "outerFuncで宣言された変数"
list.also {
println("ラムら式はクロージャなので、${outerVal}にアクセスできる。")
}.forEach returnLamda@{
// このreturnは、このラムダ式だけをリターンできる
if (it == "ReturnStr") return@returnLamda
println(it)
}
println("End of outerFunc")
}
Called outerFunc
ラムら式はクロージャなので、outerFuncで宣言された変数にアクセスできる。
suzuki
yamada
tanaka
End of outerFunc
上記の例のように、明示的にラベルを作成しなくても、暗黙的ラベルを利用するとより簡単にリターンすることもできます。
fun main(args: Array) {
outerFunc(listOf("suzuki", "yamada", "ReturnStr", "tanaka"))
}
fun outerFunc(list: List) {
println("Called outerFunc")
val outerVal = "outerFuncで宣言された変数"
list.also {
println("ラムら式はクロージャなので、${outerVal}にアクセスできる。")
}.forEach {
// 暗黙的ラベルを利用する
if (it == "ReturnStr") return@forEach
println(it)
}
println("End of outerFunc")
}
Called outerFunc
ラムら式はクロージャなので、outerFuncで宣言された変数にアクセスできる。
suzuki
yamada
tanaka
End of outerFunc