以下內(nèi)容參考這篇文章,僅做記錄:
http://www.liying-cn.net/kotlin/docs/reference/returns.html
你可能會(huì)好奇张吉,對(duì)Kotlin中的一些用法感到困惑,比如:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
btn_login.setOnClickListener({
val phone = et_phone.text.toString().trim()
val password = et_password.text.toString().trim()
if (TextUtils.isEmpty(phone)) {
ToastUtils.showShortToast(this, "手機(jī)號(hào)不能為空")
return@setOnClickListener
}
if (!ValidateUtils.isMobile(phone)) {
ToastUtils.showShortToast(this, "請(qǐng)輸入正確手機(jī)號(hào)")
return@setOnClickListener
}
if (TextUtils.isEmpty(password)) {
ToastUtils.showShortToast(this, "密碼不能為空")
return@setOnClickListener
}
if (password.length < 6 || password.length > 16) {
ToastUtils.showShortToast(this, "請(qǐng)輸入6-16位密碼")
return@setOnClickListener
}
getCampus(phone, password)
})
btn_forget_password.setOnClickListener({
val phone = et_phone.text.toString().trim()
startActivity(
Intent(this@LoginActivity, ForgetPasswordActivity::class.java).putExtra("phone",
phone))
})
上面是我從登錄功能中截取的一段代碼,我們來著重看下面這句:
if (password.length < 6 || password.length > 16) {
ToastUtils.showShortToast(this, "請(qǐng)輸入6-16位密碼")
return@setOnClickListener
}
這個(gè)@setOnClickListener是個(gè)什么鬼呢?
其實(shí)我們被編譯器的顏色誤導(dǎo)了算色,這個(gè)@標(biāo)記的是return,也就是 return@
Kotlin的返回與跳轉(zhuǎn)
Kotlin 中存在 3 種跳出程序流程的表達(dá)式:
- return. 默認(rèn)行為是, 從最內(nèi)層的函數(shù)或 匿名函數(shù) 中返回.
- break. 結(jié)束最內(nèi)層的循環(huán).
- continue. 在最內(nèi)層的循環(huán)中, 跳轉(zhuǎn)到下一次循環(huán).
所有這些表達(dá)式都可以用作更大的表達(dá)式的一部分:
val s = person.name ?: return
這些表達(dá)式的類型都是 Nothing 類型.
Break 和 Continue 的位置標(biāo)簽
Kotlin 中的任何表達(dá)式都可以用 label 標(biāo)簽來標(biāo)記. 標(biāo)簽由標(biāo)識(shí)符后面加一個(gè) @
符號(hào)構(gòu)成, 比如: abc@
, fooBar@
都是合法的標(biāo)簽(參見 語法). 要給一個(gè)表達(dá)式標(biāo)記標(biāo)簽, 我們只需要將標(biāo)簽放在它之前:
loop@ for (i in 1..100) {
// ...
}
然后, 我們就可以使用標(biāo)簽來限定 break 或 continue 的跳轉(zhuǎn)對(duì)象:
loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@loop
}
}
通過標(biāo)簽限定后, break 語句, 將會(huì)跳轉(zhuǎn)到這個(gè)標(biāo)簽標(biāo)記的循環(huán)語句之后. continue 語句則會(huì)跳轉(zhuǎn)到循環(huán)語句的下一次循環(huán).
使用標(biāo)簽控制 return 的目標(biāo)
在 Kotlin 中, 通過使用字面值函數(shù)(function literal), 局部函數(shù)(local function), 以及對(duì)象表達(dá)式(object expression), 允許實(shí)現(xiàn)函數(shù)的嵌套. 通過標(biāo)簽限定的 return 語句, 可以從一個(gè)外層函數(shù)中返回. 最重要的使用場(chǎng)景是從 Lambda 表達(dá)式中返回. 回憶一下我們?cè)?jīng)寫過以下代碼:
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return // 非局部的返回(non-local return), 直接返回到 foo() 函數(shù)的調(diào)用者
print(it)
}
println("this point is unreachable")
}
//sampleEnd
fun main(args: Array<String>) {
foo()
}
這里的 return 會(huì)從最內(nèi)層的函數(shù)中返回, 也就是, 從 foo
函數(shù)返回. (注意, 這種非局部的返回(non-local return), 僅對(duì)傳遞給 內(nèi)聯(lián)函數(shù)(inline function) 的 Lambda 表達(dá)式有效.) 如果需要從 Lambda 表達(dá)式返回, 我們必須對(duì)它標(biāo)記一個(gè)標(biāo)簽, 然后使用這個(gè)標(biāo)簽來指明 return 的目標(biāo):
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // 局部的返回(local return), 返回到 Lambda 表達(dá)式的調(diào)用者, 也就是, 返回到 forEach 循環(huán)
print(it)
}
print(" done with explicit label")
}
//sampleEnd
fun main(args: Array<String>) {
foo()
}
這樣, return 語句就只從 Lambda 表達(dá)式中返回. 通常, 使用隱含標(biāo)簽會(huì)更方便一些, 隱含標(biāo)簽的名稱與 Lambda 表達(dá)式被傳遞去的函數(shù)名稱相同.
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // 局部的返回(local return), 返回到 Lambda 表達(dá)式的調(diào)用者, 也就是, 返回到 forEach 循環(huán)
print(it)
}
print(" done with implicit label")
}
//sampleEnd
fun main(args: Array<String>) {
foo()
}
或者, 我們也可以使用 匿名函數(shù) 來替代 Lambda 表達(dá)式. 匿名函數(shù)內(nèi)的 return 語句會(huì)從匿名函數(shù)內(nèi)返回.
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // 局部的返回(local return), 返回到匿名函數(shù)的調(diào)用者, 也就是, 返回到 forEach 循環(huán)
print(value)
})
print(" done with anonymous function")
}
//sampleEnd
fun main(args: Array<String>) {
foo()
}
注意, 上面三個(gè)例子中局部返回的使用, 都與通常的循環(huán)中的 continue 關(guān)鍵字的使用很類似. 不存在與 break 直接等價(jià)的語法, 但可以模擬出來, 方法是增加一個(gè)嵌套的 Lambda 表達(dá)式, 然后在它內(nèi)部使用非局部的返回:
//sampleStart
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // 非局部的返回(non-local return), 從傳遞給 run 函數(shù)的 Lambda 表達(dá)式中返回
print(it)
}
}
print(" done with nested loop")
}
//sampleEnd
fun main(args: Array<String>) {
foo()
}
當(dāng) return 語句指定了返回值時(shí), 源代碼解析器會(huì)將這樣的語句優(yōu)先識(shí)別為使用標(biāo)簽限定的 return 語句, 也就是說:
return@a 1
含義是 “返回到標(biāo)簽 @a 處, 返回值為 1”, 而不是 “返回一個(gè)帶標(biāo)簽的表達(dá)式 (@a 1)”.
最后
這下應(yīng)該明白為什么要用return@setOnClickListener這種寫法了吧螟够,是為了指定返回的目標(biāo)位置灾梦,如果直接寫return,則會(huì)直接退出onCreate方法齐鲤,導(dǎo)致下面的代碼無法執(zhí)行斥废。