Kotlin return@xxx 的坑

Kotlin Return 到標籤

先看例子:

(1..5).forEach {
    if (it == 3) {
        return@forEach
    }
    println(it)
}
println("test over")

這段代碼執行結果是什麼?

錯誤:

1
2
test over

這裏可千萬不要想當然,認爲循環會結束。正確的結果是

1
2
4
5
test over

關於 Kotlin 中 return 使用的官方文檔:
https://www.kotlincn.net/docs/reference/returns.html

先說結論:

  1. return 默認從最直接包圍它的函數或者匿名函數返回。
  2. return 後面跟標籤,返回到標籤。

關於第一點,如下代碼:

fun test() {
    (1..5).forEach {
        if (it == 3) {
            return
        }
        println(it)
    }
    println("test over")
}

此時 return 會直接從 test() 函數中返回,輸出:

1
2

對於第二點,返回到標籤,首先名明白什麼是標籤。在 Kotlin 中任何表達式都可以用標籤來標記,標籤的格式爲標識符後面跟@ 符號,例如 abc@aaa@ 等都是有效標識符。

再看開頭的例子,爲什麼沒有跳出循環?

其實例子中 @forEach 是一個和隱式標籤,該例子等價於:

(1..5).forEach xxx@{
    if (it == 3) {
        return@xxx // 返回到 lambda 表達式的調用者
    }
    println(it)
}
println("test over")

forEach 後面跟的式一個lambda 表達式,此時的 return 實際上是返回到該 lambda 表達式的調用者,而並跳出 forEach 循環。

等價於下面使用匿名函數的實現方式,代碼如下:

(1..5).forEach(fun(value: Int) {
    if (value == 3) return // 返回到匿名函數的調用者
    println(value)
})
println("test over")

那如果想要在循環到 3 的時候跳出循環,而不跳出函數,該如何辦呢?

我們需要再調用 forEach 循環的調用處添加一個標籤,再返回到該標籤即可。如下:

run www@{
    (1..5).forEach {
        if (it == 3) {
            return@www
        }
        println(it)
    }
    println("test over")
}

知識點雖小,但是本人真真切切地踩過坑。記錄下來,也希望其他人忽視了這個知識點的人,看到以後不要踩坑了。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章