# Kotlin教程 - 3 运算与控制
# 3.1 运算符
下面介绍 Kotlin 中常见的运算符:算数运算符、赋值运算符、关系运算符。
# 1 算数运算符
算数运算符是干嘛的?
就是进行数学运算的,就是小学学的加、减、乘、除等。
Kotlin 中常见的算数运算符如下:
| 运算符 | 描述 | 示例 | 
|---|---|---|
| + | 加法 | a + b | 
| - | 减法 | a - b | 
| * | 乘法 | a * b | 
| / | 除法 | a / b | 
| % | 取余 | a % b | 
举个例子:
fun main() {
    val a = 10
    val b = 3
    println(a + b) 		// 输出 13
    println(a - b) 		// 输出 7
    println(a * b) 		// 输出 30
    println(a / b) 		// 输出 3
    println(a % b) 		// 输出 1
}
2
3
4
5
6
7
8
9
10
注意:两个整数运算得到的还是整数,所以10 / 3 = 3,没有小数部分。
如果想得到小数,则需要和浮点数进行运算,10.0 / 3 或者 10 / 3.0 。
# 2 赋值运算符
赋值运算符就是用来给变量赋值的,前面已经用到过。
# 赋值运算符
| 运算符 | 描述 | 举例 | 
|---|---|---|
| = | 赋值运算符 | 就是把 = 右边的值赋值给左边的变量。 | 
例如:
val a = 2
val b = 3
val c = a + b
2
3
除了赋值运算符,下面还有复合赋值运算符。
# 复合赋值运算符
复合赋值运算符就是经过计算后,将值赋给前面的变量。
| 运算符 | 描述 | 举例 | 
|---|---|---|
| += | 加法赋值运算符 | c += a 等效于 c = c + a | 
| -= | 减法赋值运算符 | c -= a 等效于 c = c - a | 
| *= | 乘法赋值运算符 | c *= a 等效于 c = c * a | 
| /= | 除法赋值运算符 | c /= a 等效于 c = c / a | 
| %= | 取模赋值运算符 | c %= a 等效于 c = c % a | 
举个栗子:
fun main() {
    var a = 5
    val b = 3
    a += b // a = a + b
    println(a) // 8
    
    a = 5
    a -= b // a = a - b
    println(a) // 2
    a = 5
    a *= b // a = a * b
    println(a) // 15
}
2
3
4
5
6
7
8
9
10
11
12
13
14
复合赋值运算符感觉这么写可读性还变差了,有什么好处呢?
- 代码更加简练;
- 执行效率更高。
# 3 自增自减运算符
Kotlin 中的没有自增自减运算符( ++和-- ),又可以少学习一点东西。
# 4 关系运算符
关系运算符也就是比较运算符,主要有以下几种:
| 运算符 | > | < | >= | <= | == | != | 
|---|---|---|---|---|---|---|
| 含义 | 大于 | 小于 | 大于等于 | 小于等于 | 等于 | 不等于 | 
举个栗子:
fun main() {
    val a = 10
    val b = 3
    println(a == b) // false
    println(a != b) // true
    println(a > b) // true
    println(a < b) // false
    println(a >= b) // true
    println(a <= b) // false
}
2
3
4
5
6
7
8
9
10
11
关系运算符得到的结果是 Boolean 类型(true|false),在后面可以通过使用关系运算符来进行条件的判断。例如身高大于120cm就要买儿童票等场景。
# 5 逻辑运算符
主要有以下三种:
| 运算符 | && | || | ! | 
|---|---|---|---|
| 含义 | 与,两边条件同时满足 | 或,两边条件满足一个即可 | 非,取反值,真为假,假为真 | 
举个栗子:
fun main() {
    val a = true
    val b = false
    
    println(a && b) // false
    println(a || b) // true
    println(!a) // false
}
2
3
4
5
6
7
8
可以看到逻辑运算符可以用来判断多个 Boolean 类型的条件:
fun main() {
    val a = 3
    val b = 12
    println(a > 5 && b > 10) // false
    println(a > 5 || b > 10) // true
    println(!(a > 5)) // true
}
2
3
4
5
6
7
8
!(a > 5) 是将 a > 5 的结果取反。 a > 5 结果为false,取反则为true。
# 逻辑运算符的优先级
优先级:! > && > ||
举个栗子:
fun main() {
    val result = !(1 < 2) && 3 == 3 || 1 == 3 && 2 <= 3
    print(result) // 打印:false
}
2
3
4
可以将逻辑运算的结果赋值给一个变量的。当一个逻辑运算语句中同时包含与、或 、 非运算的时候,会按照优先级进行运算。
所以上面先运算  !(1 < 2),然后运算 !(1 < 2) && 3 == 3,然后运算 1 == 3 and 2 <= 3,最后运算||两边的结果。
# 逻辑短路
逻辑短路就是在进行逻辑运算的时候,如果已经能够得到最后的值,就不会再继续进行判断了。
只有 与运算符 && 和 或运算符 || 存在逻辑短路。
举个栗子:
fun main() {
    val num = 10
    val b = num > 20 && num < 40
    println(b)
}
2
3
4
5
在执行上面代码的时候,num > 20 已经不成立了,而 && 运算需要两边都满足,所以后面的条件成不成立都不会影响最终逻辑表达式的结果,所以 && 后面的 num < 40 就不会再继续判断了,这就是逻辑短路。
同样 || 运算符:
fun main() {
    val num = 10
    val b = num < 20 || num > 40
    println(b)
}
2
3
4
5
在执行上面代码的时候,num < 20 已经成立了,|| 运算只要一边满足即可,所以整个逻辑表达式肯定是成立的,所以 || 后面的 num > 40 就不会继续判断了。
# 3.2 判断语句
判断在生活中无处不在,例如我们登录某个系统,需要判断密码是否正确,正确才能登录,否则登录失败。

# 1 if-else 语句
通过 if else 来进行条件的判断,举个栗子:
fun main() {
    var password = "1234"
    if (password == "1234") {
        println("密码正确")
    }
    else {
        println("密码错误")
    }
}
2
3
4
5
6
7
8
9
10
如果 if 后面的条件成立,则执行 if 后的操作,否则就执行 else 后的操作。所以上面会输出 密码正确。
if 后面的条需要 Boolean 类型的值、变量或表达式,一般情况下,我们通过 关系运算 和 逻辑运算 得到 Boolean 结果,也就是 true 或 false 。
也可以不需要 else 操作:
fun main() {
    var intValue = 5
    if (intValue > 0 && intValue < 10) {
        intValue += 2       // +2
    }
    println(intValue)
}
2
3
4
5
6
7
如果要执行的语句只有一行代码,可以省略 {} ,举个栗子:
fun main() {
    var password = "1234"
    if (password == "1234") 
        println("密码正确") 
    else 
        println("密码错误")
}
2
3
4
5
6
7
8
Kotlin 中的 if 表达式与传统的 if-else 语句不同,它具有一个重要的特性:它可以产生一个值作为其结果,而不仅仅是用于控制程序的执行流程。这使得 if 表达式在赋值、返回值计算等方面非常有用。
举个栗子:
fun main() {
    val a = 5
    val result = if (a > 3) {       // result 的指为操作中的最后一个语句的结果
        println("条件为真")
        a + 5
    } else {
        println("条件为假")
        15
    }
    println(result)
}
2
3
4
5
6
7
8
9
10
11
12
13
执行结果为10,因为 result 的值为操作中的最后一个语句的结果。
如果最后一个语句没有结果呢?例如:
fun main() {
    val a = 5
    val result = if (a > 3) {       // result 的指为 操作中的最后一个语句的结果
        println("条件为真")
    } else {
        println("条件为假")
        15
    }
    println(result)
}
2
3
4
5
6
7
8
9
10
11
12
上面执行后,result 的值为 kotlin.Unit ,kotlin.Unit 表示一个特殊的类型,它类似于其他编程语言中的 void。kotlin.Unit 表示没有返回值。
通过  if 表达式返回值的特性,可以实现便捷的判断,例如求两个数中的最大值:
fun main() {
    val a = 5
    val b = 7
    
    val max = if (a > b) a else b			// 如果a>b,返回a,否则返回b
    println(max)
}
2
3
4
5
6
7
如果a>b,返回a,否则返回b,因为操作只有一行语句,所以可以省略 {} ,结合  if 表达式返回值的特性,实现相关逻辑更为简介,有点类似其他语言的三元运算符 ?: 。
# 2 if-elseif-else 语句
if-else 只能进行是和否的判断。
if-elseif-else 可以进行多条件判断。
举个栗子:
给出成绩,经过判断,打印出输入的成绩是优秀、良好、中等、及格还是不及格。
fun main() {
    val score = 85
    if (score < 0 || score > 100) {
        print("成绩不正确")
    } else if (score >= 90) {
        print("优秀")
    } else if (score >= 80) {
        print("良好")
    } else if (score >= 70) {
        print("中等")
    } else if (score >= 60) {
        print("及格")
    } else {
        print("不及格")
    }
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
else-if 可以有多个,最后的 else 也是可以省略。
当满足一个条件后,其他的条件就不会再判断了,如果所有条件都不满足,会执行 else。所以上面输出的结果是:良好。
if-else语句都是可以相互嵌套的,可以在 if-else 判断中再进行 if-else 判断。
# 3 when语句
when 语句类似于其他语言的
switch,但是它比switch更加强大,判断条件可以使用表达式。
when 语句也是一种判断语句,如果判断的条件比较多,可以使用 when 语句替换 if 判断。
以下是一个示例代码,通过数字判断季节:
fun main() {
    var x = 2;
    when (x) {
        0 -> print("春季")
        1 -> print("夏季")
        2 -> print("秋季")
        3 -> print("冬季")
        else -> {
            print("季节有误")
        }
    }
}
2
3
4
5
6
7
8
9
10
11
12
when 将它的参数和后面所有的分支条件顺序比较,满足哪个分支就执行分支后的代码,满足一个条件就不会继续匹配其他的条件。如果都不满足则执行 else 中的代码。
else 代码块可以省略。
执行结果:
秋季
合并分支
如果多个分支要执行的操作是一样的,可以将多个条件进行合并:
fun main() {
    var x = 2;
    when (x) {
        0,1 -> print("上半年,春季或夏季")				// 0或1的时候,执行的操作是一样的,合并判断条件
        2,3 -> print("下半年,秋季或冬季")
        else -> {
            print("季节有误")
        }
    }
}
2
3
4
5
6
7
8
9
10
使用变量、in、is
分支判断中还可以使用 变量、in 、!in、is 判断:
fun main() {
    var x = 10
    var y = 10
    when (x) {
        y -> print("x和y相等")								 // 判断x和y的值是否相等
        in 1..10 -> print("1<=x<=10")        // 判断x是否在指定范围
        !in 1..10 -> print("1<=x<=10")       // 判断x是否不在指定范围
        is Int -> print("x是整数")            // 判断x是否是整数
        else -> print("不匹配")
    }
}
2
3
4
5
6
7
8
9
10
11
注意:满足一个条件就不会判断后面的条件
省略参数
when 语句还可以省略参数,所有的分支条件都是逻辑判断,当满足该分支时则执行该分支:
fun main() {
    var x = 10
    var y = 5
    when {
        x < y -> print("x和y相等")                     // 判断x和y是否相等
        x in 1..10 -> print("1<=x<=10")         			// 判断x是否在指定范围
        y is Int -> print("x是整数")                   // 判断y是否是整数
        else -> print("不匹配")
    }
}
2
3
4
5
6
7
8
9
10
when语句返回值
和 if 语句一样,when 语句也是可以返回值的。
举个栗子:
fun main() {
    val x = 5
    val result = when (x) {
        1 -> "One"
        2 -> "Two"
        else -> {
            println("No match")		// 输出 "No match"
            "Other"
        }
    }
    println(result) // 输出 "Other"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
result 的结果是 "Other",因为没有匹配到任何分支。因为when语句的结果,就是匹配到的分支的最后一条语句的结果。如果分支最后一条语句没有返回值,则返回 kotlin.Unit,表示没有返回值。同样,如果没有匹配到分支,返回的是 else 操作的最后一条语句的结果。
# 3.3 循环语句
循环在日常生活中也很常见,例如我们要重复做某件事,就需要用到循环,循环不停的做某件事。

举个栗子,每天向小红送一条玫瑰花,坚持送100天,这个应该怎么实现呢?
# 1 while 循环
可以使用While进行循环操作。
fun main() {
    var i = 1
    while (i <= 100) {
        println("第${i}天,送你一朵玫瑰花")
        i += 1
    }
}
2
3
4
5
6
7
代码执行到while,会判断是否满足条件,如果满足,就会进入while循环,执行完成,会重新判断while后面的条件,如果满足会继续循环,如果不满足就不在进入循环。
我们一开始定义了 i 为 1,指定到while循环时,先判断 i 是否小于等于100,如果小于等于100,则进入到循环,打印语句,然后将 i 加1,然后再执行while后面的条件判断,判断 i <= 100,这样一直循环执行,当 i = 101时,刚好已经执行了100次,且不再满足 i < =100,此时终止循环。
注意,一定要对 i 进行累加,如果 i 不进行累加,永远会满足 i <= 100,那么循环将永远不会结束,变成死循环。
执行结果:
第1天,送你一朵玫瑰花
第2天,送你一朵玫瑰花
……
第99天,送你一朵玫瑰花
第100天,送你一朵玫瑰花
我们在计数的时候,i 也可以从0开始,例如:
void main() {
  
  int i = 0;
  while (i < 100) {
    print("第${i + 1}天,送你一朵玫瑰花");
    i += 1;
  }
  
}
2
3
4
5
6
7
8
9
判断的条件的设定是很灵活的,根据实际需求来就可以了,不是一成不变的。
练习:计算从1累加到100的和
fun main() {
    var sum = 0 // 定义一个变量,存储累加的和
    var i = 1 // 定义一个变量,标识累加到几了,从1开始累加
    while (i <= 100) {
        sum += i // 将和累加
        i += 1 // 将i加1,继续累加
    }
    println("1~100的和为:${sum}") // 打印最终的结果
}
2
3
4
5
6
7
8
9
10
11
执行结果:
1~100的和为:5050
# 2 do-while 循环
do...while 循环与 while 循环的区别在于,do...while 循环先执行一次循环体中的代码,再检查条件是否为真。如果条件为真,则继续执行循环体中的代码。
举个栗子,再送一遍花:
fun main() {
    var i = 1
    do {
        println("第${i}天,送你一朵玫瑰花")
        i += 1
    } while (i <= 100)
}
2
3
4
5
6
7
8
do...while 循环会确保至少执行一次代码块。
# 3 for循环与区间
for 循环主要是用来迭代遍历可迭代对象的,也就是用来依次访问某个数据集合中的元素。
在介绍 for 循环之前,先介绍另一个概念,区间。
# 区间
区间(Range)是一个表示一组连续数值的概念。Kotlin 提供了两种类型的区间:闭区间和半开区间。
闭区间(Closed Range):
- 闭区间包含起始值和结束值,表示一个从起始值到结束值的范围。
- 语法:start..end
举个栗子:
var a = 1..10;
a 变量就表示 1、2、3、4、5、6、7、8、9、10 这个 1~10 的区间。
半开区间(Half-Open Range):
- 半开区间包含起始值但不包含结束值,表示一个从起始值到结束值的范围,但结束值不包括在内。
- 语法:start until end
举个栗子:
var a = 1 until 10;
a 变量就表示 1、2、3、4、5、6、7、8、9 这个 1~10但是不包括10 的区间。
下面举栗子进行介绍:
in 在逻辑表达式中的使用
fun main() {
    var i = 5
    if (i in 1..10) { // 判断i是否在1~10之间,等同于 1 <= i && i <= 10
        println(i)
    }
  
  	if (i in 1 until 10) { // 判断i是否在1~10之间,不包括10,等同于 1 <= i && i < 10
        println(i)
    }
}
2
3
4
5
6
7
8
9
10
in 可以判断是否在某个区间,!in 还可以判断不在某个区间:
fun main() {
    var i = 15
    if (i !in 1..10) { // 判断i是否在1~10之间,等同于 i < 1 或 i > 10
        println(i)
    }
}
2
3
4
5
6
in 在 for 循环中使用
fun main() {
    for (i in 1..10) {		// 遍历1~10
        println(i)
    }
  
  	for (i in 1 until 10) {		// 遍历1~10,不包括10
        println(i)
    }
}
2
3
4
5
6
7
8
9
for 循环会依次取出区间中的元素,i 表示每次取出的元素。
在使用 for 循环的时候,还可以指定步长。
举个栗子:
fun main() {
    for (i in 1..10 step 2) {		// 遍历1~10
        println(i)
    }
}
2
3
4
5
数据结果为:1 3 5 7 9
范围能否从大到小写呢,例如 10..1
for (i in 10..1) {		// 结果是什么都没有输出
    println(i)
}
2
3
上面的代码不能输出任何内容,如果要倒序的话,需要使用 downTo
for (i in 10 downTo 1) {		// 遍历10~1
    println(i)
}
2
3
输出结果为10到1。
同样倒序也可以使用step
for (i in 10 downTo 1 step 2) {    // 遍历10~1,步长为2,输出偶数
    println(i)
}
2
3
输出结果为:10 8 6 4 2
# 4 循环嵌套
循环是可以相互嵌套的,while和for循环中可以再次嵌套while或for循环。
例如每天给小红送10多玫瑰花,坚持100天。
fun main() {
    var day = 1 // 记录第几天
    while (day <= 100) {            // 外层循环用于循环天数
        for (roseCount in 1..10) {            // 内层循环用于循环花的朵数
            println("第${day}天,第${roseCount}朵玫瑰花")
        }
        day += 1 // 天数+1
    }
}
2
3
4
5
6
7
8
9
10
# 5 中断循环
我们在前面终止循环,主要是靠不满足条件时自动跳出。这样的话,必须每一次的循环都执行完成,到达条件判断的时候才能跳出。
但是有时候,我们不得不提前退出循环,或者终止当前的循环继续后面的循环,这个时候就需要 break 和 continue关键字了。
# break 语句
break 关键字用于直接结束当前所在的循环。
举个栗子:
如果一个循环,想在执行第三次的时候跳出:
fun main() {
    var i = 0
    while (i < 10) {
        if (i == 3) {
            break
        }
        println("i=${i}")
        i++
    }
}
2
3
4
5
6
7
8
9
10
11
执行结果:
i=0 i=1 i=2
可以看到 i = 3 时,跳出了循环。
break只会跳出其所在的循环
fun main() {
    for (i in 0..9) {
        for (j in 0..9) {
            if (j == 3) {
                break
            }
            println("i=${i}, j=${j}")
        }
    }
}
2
3
4
5
6
7
8
9
10
上面的代码,break只能跳出内部的那一个循环。
# continue 语句
continue的作用是中断本次循环,直接进入下一次循环。
举个栗子:
循环5次,在第三次的时候跳过,继续后面的执行:
fun main() {
    for (i in 0..4) {
        if (i == 3) {
            continue
        }
        println("i=${i}")
    }
}
2
3
4
5
6
7
8
执行结果:
i=0 i=1 i=2 i=4
# 死循环
在使用while循环的时候,一定要注意判断条件,否则容易编程死循环。
例如,直接设置循环条件为True:
while (true) {
    println("死循环");
}
2
3
或者,忘记更新判断条件中的变量值,也会变成死循环:
int i = 0
while (i < 10) {
    println("死循环");
}
2
3
4
死循环不一定是不对的,有时候我们还需要死循环帮我们做一些事情,要根据实际需求来。
# 6 练习
随机生成一个1-100的整数,然后在键盘输入数字来猜,猜不对,提示大了还是小了,猜对了,跳出循环。
在这里我们需要生成一个随机数,所以需要引入生成随机数的包,使用 import kotlin.random.Random 来引入,然后使用 Random.nextInt() 函数来生成一个 1~100 的整数。
import kotlin.random.Random
fun main() {
    val goal = Random.nextInt(1, 101) // 随机生成 1 到 100 之间的整数
    println("欢迎参加猜数字游戏!")
    println("我已经生成了一个1到100之间的整数,请开始猜测。")
    while (true) {
        print("请输入你的猜测:")
        val input = readLine()
        if (input == null || "" == input) {
            println("请输入有效的整数")
            continue
        }
        val value = input.toInt();
        if (value > goal) {
            println("猜大了!");
        } else if (value < goal) {
            println("猜小了!");
        } else {
            println("猜对了!");
            break;
        }
    }
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
