《Kotlin从小白到大牛》第9章:程序流程控制

第9章 程序流程控制

程序设计中的流程控制有三种结构,即顺序、分支和循环结构。Kotlin中的流程控制结构分类如下:
o 分支结构:if和when
o 循环结构:while、do-while和for
o 跳转结构:break、continue和return

9.1 if分支结构

分支结构提供了一种控制机制,使得程序具有了“判断能力”,能够像人类的大脑一样分析问题。分支结构又称条件结构,条件结构使部分程序可根据某些表达式的值被有选择地执行。在Kotlin语言中分支结构有if和when,本节先介绍if结构。

9.1.1 if结构当做语句使用
在Kotlin语言中if和when结构都是表达式,表示式是有返回值的,而语句没有。在前面4.4节讨论过这个问题。但是if表达式也可以当成if语句使用,这与传统if语句完全一样,下面先if结构当做语句使用。
if语句有三种结构:if结构、if-else结构和else-if结构三种。
1.f结构
if (条件表达式) {
语句组
}
如果条件表达式为true就执行语句组,否则就执行if结构后面的语句。
2. if-else结构
if (条件表达式) {
语句组1
} else {
语句组2
}
当程序执行到if语句时,先判断条件表达式,如果值为true,则执行语句组1,然后跳过else语句及语句组2,继续执行后面的语句。如果条件表达式的值为false,则忽略语句组1而直接执行语句组2,然后继续执行后面的语句。
3. else-if结构
if (条件表达式1) {
语句组1
} else if (条件表达式2) {
语句组2
} else if (条件表达式3) {
语句组3

} else if (条件表达式n) {
语句组n
} else {
语句组n+1
}
可以看出,else-if结构实际上是if-else结构的多层嵌套,它明显的特点就是在多个分支中只执行一个语句组,而其他分支都不执行,所以这种结构可以用于有多种判断结果的分支中。
在这里插入图片描述
示例如下:
//代码文件:chapter9/src/com/a51work6/ch9.1.1.kt
package com.a51work6

fun main(args: Array) {
// 1. if结构
val score = 95
if (score >=85) {
println(“您真优秀!”)
}
if (score <60) {
println(“您需要加倍努力!”)
}
if (score >=60 && score < 85) {
println(“您的成绩还可以,仍需继续努力!”)
}

// 2. if-else结构
if (score <60) {     

println(“不及格”)
} else {
println(“及格”)
}

// 3. else-if结构
val testScore =76
val grade: Char
if (testScore>= 90) {
    grade = 'A'
} else if

(testScore >= 80) {
grade = ‘B’
} else if
(testScore >= 70) {
grade = ‘C’
} else if
(testScore >= 60) {
grade = ‘D’
} else {
grade = ‘F’
}
println("Grade = " + grade)
}
运行结果如下:
您真优秀!
及格
Grade = C
上述代码如果对于Java或C等其他语句有些熟悉的读者,应该很容易读懂,这不再赘述。

9.1.2 if表达式
Kotlin语言主张代码简洁,9.1.1节代码显然不够简洁,Kotlin使用if表达式让代码简洁。if表达式中每个代码块的最后一个表达式就是它的返回值。因为要求有返回值,所以没有if结构,只有if-else和else-if两种结构。具体说明如下:
1.if-else结构
val(或var) bar = if (条件表达式) {
语句组1
表达式
} else {
语句组2
表达式
}
当程序执行到if语句时,先判断条件表达式,如果值为true,则执行语句组1所在代码块执行,完成后计算表达式。然后跳过else语句所在的语句组2代码块执行,完成后计算表达式,最后结束将表达式计算结果赋值给变量bar。

  1. else-if结构
    val(或var) bar = if (条件表达式1) {
    语句组1
    表达式
    } else if (条件表达式2) {
    语句组2
    表达式
    } else if (条件表达式3) {
    语句组3
    表达式

    } else if (条件表达式n) {
    语句组n
    表达式
    } else {
    语句组n+1
    表达式
    }
    在这里插入图片描述
    示例如下:
    //代码文件:chapter9/src/com/a51work6/ch9.1.2.kt
    package com.a51work6

fun main(args: Array) {

val score = 95

// 1. if-else结构
val result1 = if (score < 60) {      ①
    println("不及格")
} else {
    println("及格")
}       ②

val result2 = if (score < 60) {      ③
    println("不及格")
    //TODO
    "重新考试"         ④
} else {
    println("及格")
    //TODO
    "通过考试"         ⑤
}        ⑥

// 2. else-if结构
val testScore = 76
val grade: Char = if (testScore >=90)  ⑦
    'A'
else if (testScore >= 80)
    'B'
else if (testScore >= 70)
    'C'
else if (testScore >= 60)
    'D'
else
    'F'                                             ⑧
    
println("Grade = " + grade)

}
上述代码第①行~第②行是使用if-else结构的if表达式,虽然把结果赋值给result1变量,但这个表达式结果事实上没有任何的值,因为它的两个代码块中最后一条不是个表达式,是一个println语句,它是没返回值的。这种场景下使用if表达式就没有实际意义,而是考虑使用if语句结构。
代码第③行~第⑥行也是if-else结构的if表达式,两个代码块最后都有表达式,见代码第④行和第⑤行。结果将"通过考试"字符串赋值给result2变量,返回值是有实际意义的。
代码第⑦行~第⑧行是else-if结构的if表达式,每个代码块都只有一条表达式,因此可以省略大括号。

9.2 when多分支结构

when提供多分支程序结构,替代Java中C语言风格的switch语句,C、C++、Objective-C和Java等多种语言都采用该种风格。when彻底地颠覆了自C语言风格以来大家对于switch的认知,这个颠覆表现在以下三个方面。
1.C语言风格的switch只能比较离散的单个的整数(或可以自动转换为整数)表达式,而when可以使用整数、浮点数、字符、字符串,以及任何可以比较的类型表达式,而且它比较的数据可以是离散的也可以是连续的范围。
2.when中的每个分支不需要添加break语句,分支执行完成就会跳出when语句。
3.when可以作为表达式使用,并且可以将一个结果赋值给其他变量,或者与其他表达式进行计算。而C语言风格的switch语句不能作为表达式。

9.2.1 when结构当做语句使用
下面先介绍一下when结构当做语句使用,语法结构如下:
when (表达式) {
分支条件表达式1 -> {
语句组1
}
分支条件表达式2 -> {
语句组2
}

分支条件表达式n -> {
语句组n
}
else -> {
语句组n+1
}
}
在运行时“表达式”计算结果,会与每个分支中的“分支条件表达式”进行匹配,直到找到一个分支,然后进入该分支的代码块执行,执行完成结束when语句。when结构当做语句时,最后的else分支可以省略。另外,如果语句组所在的代码块只有一条语句,可以省略大括号。
示例代码如下:
//代码文件:chapter9/src/com/a51work6/ch9.2.1.kt
package com.a51work6

fun main(args: Array) {

val testScore = 75  //设定一个数值用来测试
when (testScore / 10) {     ①
    9 -> {                      ②
        println('优')
    }
    8 -> println('良')
    7, 6 -> println('中')   ③
    else -> println('差')    
}

val level = "优"    //设定一个数值用来测试
var desc = ""   //接收返回值
when (level) {                  ④
    "优" -> desc ="90分以上"
    "良"-> desc = "80分~90分"
    "中"-> desc = "70分~80分"
    "差"-> desc = "低于60分"

}
println("说明 = " + desc)
}
运行结果如下:

说明 = 90分以上
上述代码第①行when语句实现了将100分制转换为:“优”、“良”、“中”、“差”评分制,其中7分和6分都是“中”成绩,见代码第③行把7和6情况放到一个分支中,当成一种情况考虑,它们之间用逗号(,)分隔。代码第②行分支代码块没有省略大括号,其他的分支代码块都省略了。
代码第④行是when语句省略了else分支,而且事实上这个when语句是有返回值的,所以它最好采用when表达式方式。
Kotlin中的when语句很灵活,上述示例中表达式结果比较是否等于分支条件表达式结果。此外,还可以使用in或者!in表达式结果是否在一个范围或集合中;可以用is或者!is表达式结果是否是某一类型的对象。
when语句还可以省略表达式,此时分支条件表达式可以是单纯的布尔值,示例代码如下:
when {//省略表达式
testScore >= 90 -> println(‘优’) //分支条件表达式单纯的布尔值
else -> println(‘良’)
}

9.2.2 when表达式
9.2.1节的when语句示例代码显然还不够简洁,与if表达式类似,when表达式也可以使得代码变得更加简洁。when表达式语法结构如下:
val(或var) bar = when (表达式) {
分支条件表达式1 -> {
语句组1
表达式
}
分支条件表达式2 -> {
语句组2
表达式
}

分支条件表达式n -> {
语句组n
表达式
}
else -> {
语句组n+1
表达式
}
}
when表达式每一个分支最好是一条表达式,最后结束将表达式计算结果赋值给变量bar。需要注意的是when表达式不能省略else分支,除非编译器能判断出来,程序已经覆盖了所有的分支条件,这种情况一般会在when与枚举类结合使用时出现,因为枚举类的成员常量是固定几个取值。when与枚举类使用细节将在11.9节详细介绍这里不再赘述。
示例代码:
//代码文件:chapter9/src/com/a51work6/ch9.2.2.kt
package com.a51work6

fun main(args: Array) {

val testScore = 75  //设定一个数值用来测试
val grade = when (testScore / 10) {     
    9 -> '优'
    8 -> '良'
    7, 6 -> '中'
    else -> '差'
}
println("Grade = " + grade)

val level = "优"    //设定一个数值用来测试
val desc = when (level) {
    "优"-> "90分以上"
    "良"-> "80分~90分"
    "中"-> "70分~80分"
    "差"-> "低于60分"
    else -> "无法判断"
}
println("说明 = " + desc)

}
上述代码中使用了两个when表达式,从代码中可见when表达式都没有省略else分支,读者可以将else分支注释掉,看一看是否能够编译通过。

9.3 循环结构

循环语句能够使程序代码重复执行。Kotlin支持三种循环结构:while、do-while、和for。for和while循环是在执行循环体之前测试循环条件,而do-while是在执行循环体之后测试循环条件。这就意味着for和while循环可能连一次循环体都未执行,而do-while将至少执行一次循环体。

9.3.1 while语句
while语句是一种先判断的循环结构,格式如下:
while (循环条件) {
语句组
}
while循环没有初始化语句,循环次数是不可知的,只要循环条件满足,循环就会一直进行下去。
在这里插入图片描述
下面看一个简单的示例,代码如下:
//代码文件:chapter9/src/com/a51work6/ch9.3.1.kt
package com.a51work6
fun main(args: Array) {
var i = 0
while (i * i < 100_000) {//采用下划线分割数值可读性好
i++
}
println("i = " + i) //输出结果是i = 317
println("i * i = " + i * i)
//输出结果是i * i = 100489
}
上述程序代码的目的是找到平方数小于100000的最大整数。使用while循环需要注意几点,while循环条件语句中只能写一个表达式,而且是一个布尔型表达式,那么如果循环体中需要循环变量,就必须在while语句之前对循环变量进行初始化。本例中先给i赋值为0,然后在循环体内部必须改变循环变量的值,否则将会发生死循环。

9.3.2 do-while语句
do-while语句的使用与while语句相似,不过do-while语句是事后判断循环条件结构,语句格式如下:
do {
  语句组
} while (循环条件)
do-while循环没有初始化语句,循环次数是不可知的,不管循环条件是否满足,都会先执行一次循环体,然后再判断循环条件。如果条件满足则执行循环体,不满足则停止循环。
在这里插入图片描述
下面看一个示例代码:
//代码文件:chapter9/src/com/a51work6/ch9.3.2.kt
package com.a51work6
fun main(args: Array) {
var i = 0
do {
i++
} while (i * i < 100_000)//采用下划线分割数值可读性好
println("i = " + i) //输出结果是i = 317
println("i * i = " + i * i)
//输出结果是i * i = 100489
}
该示例与上一节的示例是一样的,都是找到平方数小于100000的最大整数。输出结果也是一样的。

9.3.3 for语句
Kotlin语言中没有C语言风格的for语句,它的for语句相等于Java中增强for循环语句,只用于对范围、数组或集合进行遍历。
范围示例代码如下:
//代码文件:chapter9/src/com/a51work6/ch9.3.3.kt

for (num in 1…9) { //使用范围运算符
println("$num x $num = ${num *
num}")
}
输出结果如下:
1 x 1 = 1
2 x 2 = 4
3 x 3 = 9
4 x 4 = 16
5 x 5 = 25
6 x 6 = 36
7 x 7 = 49
8 x 8 = 64
9 x 9 = 81
上述代码是计算1~9的平方表,for循环中1…9范围,取值是大于等于1小等于9,范围将在9.5节详细介绍,这里不再赘述。num是从范围取出的元素,省略了var或val声明,注意num不是C语言风格for语句中的循环变量,它是范围、数组或集合中取出的元素。
集合遍历示例代码如下:
//代码文件:chapter9/src/com/a51work6/ch9.3.3.kt

// 声明并初始化Int数组
val numbers = intArrayOf(43, 32, 53, 54, 75, 7, 10) ①

for (item in numbers) { ②
println(“Count is:KaTeX parse error: Expected 'EOF', got '}' at position 9: item") }̲ 上述代码第①行是使用intA…i] =${numbers[i]}”)
}
运行结果:
numbers[0] = 43
numbers[1] = 32
numbers[2] = 53
numbers[3] = 54
numbers[4] = 75
numbers[5] = 7
numbers[6] = 10

9.4 跳转语句

跳转语句能够改变程序的执行顺序,可以实现程序的跳转。Kotlin中主要有3种跳转语句:break、continue和return。本节重点介绍break和continue语句的使用。return可以用于函数或Lambda表达式返回数据,详细内容将10.1节和14.3.4节介绍,本节暂不介绍。

9.4.1 break语句
break语句可用于上一节介绍的while、do-while和for循环结构,它的作用是强行退出循环体,不再执行循环体中剩余的语句。
在循环体中使用break语句有两种方式:带有标签和不带标签。语法格式如下:
break //不带标签
break@label //带标签,label是标签名
不带标签的break语句使程序跳出所在层的循环体,而带标签的break语句使程序跳出标签指示的循环体。
下面看一个示例,代码如下:
val numbers = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

for (i in numbers.indices) {
if (i == 3) {
// 跳出循环
break
}
println(“Count is: " + numbers[i])
}
在上述程序代码中,当条件i==3的时候执行break语句,break语句会终止循环,程序运行的结果如下:
Count is: 1
Count is: 2
Count is: 3
break还可以配合标签使用,示例代码如下:
label1@ for (x in 0…4) { ①
for (y in 5 downTo 1) { ②
if (y == x) {
// 跳转到label1指向的外循环
break@label1 ③
}
println(”(x,y) =( x , x, x,y)")
}
}
println(“Game Over!”)
默认情况下,break只会跳出最近的内循环(代码第②行for循环)。如果要跳出代码第①行的外循环,可以为外循环添加一个标签label1,注意在定义标签的时候后面跟一个@。代码第③行的break语句后面跟有@label1,注意中间没有空格,这样当条件满足执行break语句时,程序就会跳转出label1标签所指定的循环。
在这里插入图片描述
程序运行结果如下:
(x,y) = (0,5)
(x,y) = (0,4)
(x,y) = (0,3)
(x,y) = (0,2)
(x,y) = (0,1)
(x,y) = (1,5)
(x,y) = (1,4)
(x,y) = (1,3)
(x,y) = (1,2)
Game Over!
在这里插入图片描述
如果break后面没有指定外循环标签,则运行结果如下:
(x,y) = (0,5)
(x,y) = (0,4)
(x,y) = (0,3)
(x,y) = (0,2)
(x,y) = (0,1)
(x,y) = (1,5)
(x,y) = (1,4)
(x,y) = (1,3)
(x,y) = (1,2)
(x,y) = (2,5)
(x,y) = (2,4)
(x,y) = (2,3)
(x,y) = (3,5)
(x,y) = (3,4)
(x,y) = (4,5)
Game Over!
比较两种运行结果,就会发现给break添加标签的意义,添加标签对于多层嵌套循环是很有必要的,适当使用可以提高程序的执行效率。

9.4.2 continue语句
continue语句用来结束本次循环,跳过循环体中尚未执行的语句,接着进行终止条件的判断,以决定是否继续循环。
在循环体中使用continue语句有两种方式可以带有标签,也可以不带标签。语法格式如下:
continue //不带标签
continue@label //带标签,label是标签名
下面看一个示例,代码如下:
val numbers = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

for (i in numbers.indices) {
if (i == 3) {
continue
}
println("Count is: " + numbers[i])
}
程序运行结果如下:
Count is: 1
Count is: 2
Count is: 3
Count is: 5
Count is: 6
Count is: 7
Count is: 8
Count is: 9
Count is: 10
在上述程序代码中,当条件i==3的时候执行continue语句,continue语句会终止本次循环,循环体中continue之后的语句将不再执行,接着进行下次循环,所以输出结果中没有3。

带标签的continue语句示例代码如下:
label1@ for (x in 0…4) { ①
for (y in 5 downTo 1) { ②
if (y == x) {
continue@label1 ③
}
println("(x,y) = ( x , x, x,y)")
}
}
println(“Game Over!”)

默认情况下,continue只会跳出最近的内循环(代码第②行for循环),如果要跳出代码第①行的外循环,可以为外循环添加一个标签label1,然后在第③行的continue语句后面跟有@label1,这样当条件满足执行continue语句时,程序就会跳转出外循环。
程序运行结果如下:
(x,y) = (0,5)
(x,y) = (0,4)
(x,y) = (0,3)
(x,y) = (0,2)
(x,y) = (0,1)
(x,y) = (1,5)
(x,y) = (1,4)
(x,y) = (1,3)
(x,y) = (1,2)
(x,y) = (2,5)
(x,y) = (2,4)
(x,y) = (2,3)
(x,y) = (3,5)
(x,y) = (3,4)
(x,y) = (4,5)
Game Over!

由于跳过了x == y,因此下面的内容没有输出。
(x,y) = (1,1)
(x,y) = (2,2)
(x,y) = (3,3)
(x,y) = (4,4)

9.5 使用区间

在前面的学习过程中多次用到了区间(Range)来表示一个范围,这一节介绍一下区间。

9.5.1 表示区间
区间有闭区间、开区间和半开区间之分,在程序设计中闭区间和半闭合区间使用比较多,闭区间包含上下临界值;半开区间包含下临界值,但不包含上临界值。
闭区间含义如下:
下临界值≤ 范围 ≤上临界值
半开区间含义如下:
下临界值≤ 范围 <上临界值
在这里插入图片描述
在Kotlin语言中闭区间采用区间运算符(…)表示,而半开区间则需要使用中缀运算符until表示。示例代码如下:
//代码文件:chapter9/src/com/a51work6/ch9.5.1.kt
package com.a51work6

fun main(args: Array) {

for (x in 0..5) {   //定义闭区间包含0和5       ①
    print("$x,")
}
println()

for (x in 0 until 5) {  //定义半开区间包含0,不包含5      ②
    print("$x,")
}
println()
for (x in 'A'..'E') {  //定义闭区间包含'A'和'E'           ③
    print("$x,")
}
println()

for (x in 'A' until 'E') { //定义半开区间包含'A',不包含'E'           ④
    print("$x,")
}

}

运行结果:
0,1,2,3,4,5,
0,1,2,3,4,
A,B,C,D,E,
A,B,C,D,
上述代码中第①行和第④行使用区间运算符(…)定义了一个闭区间。代码第②行和第③行使用until中缀运算符定义了一个闭区间。

9.5.2 使用in和!in关键字
判断一个数值是否在区间中可以使用in关键字。而!in关键字,则是判断一个值不在区间中。此外,这两个关键字(in和!in)还可以判断一个数值是否集合或数组中。
示例代码如下:
//代码文件:chapter9/src/com/a51work6/ch9.5.2.kt
package com.a51work6

fun main(args: Array) {

var testscore = 80 //设置一个分数用于测试
var grade = when (testscore) {   ①
    in 90..100 -> "优"
    in 80 until 90 -> "良"
    in 60 until 80 -> "中"
    in 0 until 60 -> "差"
    else -> "无"
}                                             ②
println("Grade = " + grade)

if (testscore !in 60..100) { //使用!in关键字     ③
    println("不及格")
}
val strArray = arrayOf("刘备", "关羽", "张飞")
val name = "赵云"
if (name !in strArray) {               ④
    println(name + "不在队伍中")
}

}
上述代码第①行~第②行是使用when表达式,在分支条件表达式in关键字是否表达式testscore的值在区间中。代码第③行使用了!in关键字,判断testscore表达式值不在60…100)区间中。
另外,in和!in关键字还可以应用于集合或数组判断,代码第④行是判断name表达式值不在字符串集合strArray中。

本章小结

通过对本章内容的学习,读者可以了解到Kotlin语言的程序流程控制,其中包括分支结构(if和when)、循环语句(while、do-while和for)和跳转语句(break和continue)等。最后介绍了Kotlin区间。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值