【Kotlin】Kotlin学习二-控制流


学而不思则罔,思而不学则殆


If 表达式

在 Kotlin 中, if 是一个表达式,即它会返回一个值。 因此就不需要三元运算符(条件 ? 然后 : 否则),因为普通的 if 就能胜任这个角色
传统用法

    val a = 10
    val b = 11
    var max = a
    if (a < b) max = b
    println("max = $max")

With else

    val a = 10
    val b = 11
    val max: Int
    max = if (a > b) {
        a
    } else {
        b
    }

作为表达式

    val a = 10
    val b = 11

    val max = if (a > b) a else b
    println("max = $max")

这种方式可以替代三元符号?:

if 的分支可以是代码块,最后的表达式作为该块的值:

    val a = 10
    val b = 11
    // 作为表达式
    val max = if (a > b) {
        print("Choose a")
        a
    } else {
        print("Choose b")
        b
    }

如果你使用 if 作为表达式而不是语句(例如:返回它的值或者把它赋给变量),该表达式需要有 else 分支。

when表达式

when 取代了类 C 语言的 switch 操作符。其最简单的形式如下:

    val x = 2
    when (x) {
        1 -> print("x == 1")
        2 -> print("x == 2")
        else -> { // 注意这个块
            print("x is neither 1 nor 2")
        }
    }
    //x == 2

when 将它的参数与所有的分支条件顺序比较,直到某个分支满足条件。 when 既可以被当做表达式使用也可以被当做语句使用。如果它被当做表达式, 符合条件的分支的值就是整个表达式的值,如果当做语句使用, 则忽略个别分支的值。(像 if 一样,每一个分支可以是一个代码块,它的值是块中最后的表达式的值。)

如果其他分支都不满足条件将会求值 else 分支。 如果 when 作为一个表达式使用,则必须有 else 分支, 除非编译器能够检测出所有的可能情况都已经覆盖了[例如,对于 枚举( enum )类条目与密封( sealed )类子类型]。

如果很多分支需要用相同的方式处理,则可以把多个分支条件放在一起,用逗号分隔:

    val x = 2
    when (x) {
        0, 1 -> print("x == 0 or x == 1")
        else -> print("otherwise")
    }
    //otherwise

我们可以用任意表达式(而不只是常量)作为分支条件

    val x = 2
    when (x) {
        x * 1 -> print("s 1 encodes x")
        x * 2 -> print("s 2 encodes x")
        x * 3 -> print("s 3 encodes x")
        else -> print("s does not encode x")
    }
    //s 1 encodes x

我们也可以检测一个值在( in )或者不在( !in )一个区间或者集合中:

    val x = 21
    val validNumbers = arrayOf(1, 3, 5, 15)
    when (x) {
        in 1..10 -> print("x is in the range")
        in validNumbers -> print("x is valid")
        !in 10..20 -> print("x is outside the range")
        else -> print("none of the above")
    }
    //x is outside the range

另一种可能性是检测一个值是( is )或者不是( !is )一个特定类型的值。注意: 由于智能转换,你可以访问该类型的方法与属性而无需任何额外的检测。

    fun hasPrefix(x: Any) = when (x) {
        is String -> x.startsWith("prefix")
        else -> false
    }

    println(hasPrefix("xxx"))//false
    println(hasPrefix("prefixxxxx"))//true

when 也可以用来取代 if - else if 链。 如果不提供参数,所有的分支条件都是简单的布尔表达式,而当一个分支的条件为真时则执行该分支:

    val x = arrayOf(1, 2, 3)
    when {
        x.isEmpty() -> print("x is isEmpty")
        x.isNotEmpty() -> print("x is isNotEmpty")
        else -> print("x is else")
    }
    //x is isNotEmpty

自 Kotlin 1.3 起,可以使用以下语法将 when 的主语(subject,译注:指 when 所判断的表达式)捕获到变量中:

fun testNum() {
    val result = when (val response = getResult()) {
        200 -> "Success"
        404 -> "Not Found"
        else -> "unknown"
    }
    println(result)//Success
}

fun getResult(): Int {
    return 200
}

PS:在 when 主语中引入的变量的作用域仅限于 when 主体。

for表达式

for 循环可以对任何提供迭代器(iterator)的对象进行遍历,语法如下:

for (item in collection) print(item)

循环体可以是一个代码块。

for (item: Int in ints) {
// ……
}

如需在数字区间上迭代,请使用区间表达式:

    for (i in 1..3) {
        println(i)
    }
    //1 2 3
    for (i in 6 downTo 0 step 2) {
        println(i)
    }
    //6 4 2 0

对区间或者数组的 for 循环会被编译为并不创建迭代器的基于索引的循环。如果你想要通过索引遍历一个数组或者一个 list,你可以这么做:

    val array = arrayOf("a", "b", "c")
    println("array.indices = ${array.indices}")
    for (i in array.indices) {
        println("$i = ${array[i]}")
    }
    array.indices = 0..2
    0 = a
    1 = b
    2 = c

或者你可以用库函数 withIndex :

    val array = arrayOf("a", "b", "c")
    println(array.withIndex())
    for ((index, value) in array.withIndex()) {
        println("the element at $index is $value")
    }
    //kotlin.collections.IndexingIterable@76ed5528
the element at 0 is a
the element at 1 is b
the element at 2 is c

while表达式

while 与 do … while 照常使用

while (x > 0) {
x--
}
do {
val y = retrieveData()
} while (y != null) // y 在此处可见

返回和跳转


Kotlin 有三种结构化跳转表达式:

  • return 。默认从最直接包围它的函数或者匿名函数返回。
  • break 。终止最直接包围它的循环。
  • continue 。继续下一次最直接包围它的循环。

所有这些表达式都可以用作更大表达式的一部分:

Break 与 Continue 标签


在 Kotlin 中任何表达式都可以用标签( label )来标记。 标签的格式为标识符后跟 @ 符号,例如: abc@ 、 fooBar@ 都是有效的标签.要为一个表达式加标签,我们只要在其前加标签即可。

loop@ for (i in 1..100) {
// ……
}

现在,我们可以用标签限制 break 或者 continue :

    loop@ for (i in 1..10) {
        for (j in 1..10) {
            //if (j == 2) break@loop else println("$i $j")
            if (j == 2) break else println("$i $j")
        }
    }
    println("end")
1 1
2 1
3 1
4 1
5 1
6 1
7 1
8 1
9 1
10 1
end
    loop@ for (i in 1..10) {
        for (j in 1..10) {
            if (j == 2) break@loop else println("$i $j")
            //if (j == 2) break else println("$i $j")
        }
    }
    println("end")
    1 1
    end

添加loop标签,break直接退出了外层循环,而不是直接包围他的循环。
标签限制的 break 跳转到刚好位于该标签指定的循环后面的执行点。 continue 继续标签指定的循环的下一次迭代。

返回到标签

Kotlin 有函数字面量、局部函数和对象表达式。因此 Kotlin 的函数可以被嵌套。 标签限制的return 允许我们从外层函数返回。 最重要的一个用途就是从 lambda 表达式中返回。
在这里插入图片描述
这个 return 表达式从最直接包围它的函数即 foo 中返回。 (注意,这种非局部的返回只支持传给内联函数的 lambda 表达式。) 如果我们需要从 lambda 表达式中返回,我们必须给它加标签并用以限制 return
在这里插入图片描述
现在,它只会从 lambda 表达式中返回。通常情况下使用隐式标签更方便。 该标签与接受该lambda 的函数同名。
在这里插入图片描述
或者,我们用一个匿名函数替代 lambda 表达式。 匿名函数内部的 return 语句将从该匿名函数自身返回

fun test() {
    foo()
    println("foo end")
}

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
        if (value == 3) return // 局部返回到匿名函数的调用者,即 forEach 循环
        print("$value ")
    })
    print(" done with anonymous function")
}
1 2 4 5  done with anonymous functionfoo end

请注意,前文三个示例中使用的局部返回类似于在常规循环中使用 continue 。并没有break 的直接等价形式,不过可以通过增加另一层嵌套 lambda 表达式并从其中非局部返回来模拟:

fun test() {
    foo()
    println("foo end")
}

fun foo() {
    run loop@{
        listOf(1, 2, 3, 4, 5).forEach {
            if (it == 3) return@loop // 从传入 run 的 lambda 表达式非局部返回
            print("$it ")
        }
    }
    println(" done with nested loop")
}
1 2  done with nested loop
foo end

当要返一个回值的时候,解析器优先选用标签限制的 return,即

return@a 200

意为“返回 1 到 @a ”,而不是“返回一个标签标注的表达式 (@a 1) ”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值