三、流程控制

news2024/11/26 9:34:12

流程控制

  • 选择结构(if-else)
  • 选择结构(when)
  • 循环结构(for)
  • 循环结构(while)

经过前面的学习,我们知道,程序都是从上往下依次运行的,但是,仅仅是这样还不够,我们需要更加高级的控制语句来使得程序更加有趣。比如,判断一个整数变量,大于1则输出yes,小于1则输出no,这时我们就需要用到选择结构来帮助我们完成条件的判断和程序的分支走向。

在前面我们介绍了运算符,我们可以通过逻辑运算符和关系运算符对某些条件进行判断,并得到真或是假的结果。这一部分我们将继续使用这些运算符进行各种判断,以及实现流程控制。

选择结构(if-else)

某些时候,我们希望进行判断,只有在条件为真时,才执行某些代码,这种情况就需要使用到选择分支语句,首先我们来认识一下if语句:

if (条件判断) 判断成功执行的代码;

if的小括号中需要我们传入一个Boolean类型的结果,可以是一个Boolean变量,也可以是一个判断语句,反正只能接受true和false两种结果,比如下面的这个例子:

fun main() {
    val a = 10
    if(a == 12)  //只有当a判断等于12时,才会执行下面的打印语句
        println("Hello World!")
    println("我是后续的语句")  //if只会对紧跟着的一行代码生效,后续的内容无效
}

if会进行判断,只有判断成功时才会执行紧跟着的语句,否则会直接跳过,注意,如果我们想要在if中执行多行代码,需要使用代码块将这些代码囊括起来(实际上代码块就是将多条语句复合到一起,使用花括号囊括)所以说,我们以后使用if时,如果分支中有多行代码需要执行,就需要添加花括号,如果只有一行代码,花括号可以直接省略,包括我们后面会讲到的else、while、for语句都是这样的,就像下面这样:

fun main() {
    val a = 15
    if (a > 10) {    //只有判断成功时,才会执行下面的代码块中内容,否则直接跳过
        println("a大于10")
        println("a的值为:$a")
    }
    println("我是外层")
}

如果我们希望判断条件为真时执行某些代码,条件为假时执行另一些代码,我们可以在后面继续添加else语句:

fun main() {
    val a = 15
    if (a > 10) {    //只有判断成功时,才会执行下面的代码块中内容,否则直接跳过
        println("a大于10")
        println("a的值为:$a")
    } else {   //当判断不成功时,会执行else代码块中的代码
        println("a小于10")
        println("a的值为:$a")
    }
    println("我是外层")
}

if-else语句就像两个分支,跟据不同的判断情况从而决定下一步该做什么,这跟我们之前认识的三元运算符性质比较类似。

那如果此时我们需要判断多个分支呢?比如我们现在希望判断学生的成绩,不同分数段打印的等级不一样,比如90以上就是优秀,70以上就是良好,60以上是及格,其他的都是不及格,那么这种我们又该如何判断呢?要像这样进行连续判断,我们需要使用else-if来完成:

fun main() {
    val score = 2
    if (score >= 90) //90分以上才是优秀
        println("优秀") 
    else if (score >= 70) //当上一级if判断失败时,会继续判断这一级
        println("良好") 
    else if (score >= 60) 
        println("及格") 
    else  //当之前所有的if都判断失败时,才会进入到最后的else语句中
        println("不及格")
}

当然,if分支语句还支持嵌套使用,比如我们现在希望低于60分的同学需要补习,0-30分需要补Java,30-60分需要补C++,这时我们就需要用到嵌套:

fun main() {
    val score = 2
    if (score < 60) {   //先判断不及格
        if (score > 30) //在内层再嵌套一个if语句进行进一步的判断
            println("学习C++") 
        else 
            println("学习Java")
    }
}

除了if自己可以进行嵌套使用之外,其他流程控制语句同样可以嵌套使用,也可以与其他流程控制语句混合嵌套使用。这样,我们就可以灵活地使用if来进行各种条件判断了。

除了直接执行语句之外,我们也可以将if和else用作结果判断,比如:

fun main() {
    val score = 2
  	//这里判断socre是否大于60,是就得到Yes,否就得到No,并且可以直接赋值给变量
    val res = if (score > 60) "Yes" else "No"
}

这类似于其他语言,如Java和C中的三元运算,不过Kotlin中没有那样的三元运算符,只能使用上面的表达式,对于多行代码块的情况,默认最后一行作为返回的结果:

fun main() {
    val score = 2
    val res = if (score > 60) {
        println("不错啊期末没挂科")
        "Yes"   //代码块默认最后一行作为返回结果
    } else {
        println("不会有人Java期末还要挂科吧")
        "No"
    }
}

注意,如果需要这种返回结果的表达式,那么必须要存在else分支,否则不满足条件岂不是没结果了?

选择结构(when)

前面我们介绍了if语句,我们可以通过一个if语句轻松地进行条件判断,然后根据对应的条件,来执行不同的逻辑,当然除了这种方式之外,我们也可以使用when语句来实现,它更适用于多分支的情况:

when定义具有多个分支的条件表达式。它类似于类似Java和C语言中的switch语句,它简单的形式看起来像这样:

when (目标) {
    匹配值1 -> 代码...   //我们需要传入一个目标,比如变量,或是计算表达式等
    匹配值2 -> 代码...   //如果目标的值等于我们这里给定的匹配值,那么就执行case后面的代码
    else -> {
        代码...    //如果以上条件都不满足,就进入else中(可以没有),类似于之前的if-elseif-else
    }
}

比如现在我们要根据学生的等级进行分班,学生有ABC三个等级:

fun main() {
    val c = 'A'
    when (c) {
        'A' -> println("去尖子班!准备冲刺985大学!")
        'B' -> println("去平行班!准备冲刺一本!")
        'C' -> println("去职高深造。")
    }
}

如果将when用作表达式,则else分支必须存在,除非编译器能推断出所有可能的情况都包含分支条件,比如下面的例子:

fun main() {
    val c = 'A'
    val numericValue = when (c) {
        'B' -> 0
        'A' -> 1
        else -> 2    //还有其他情况,这里必须添加else,不然其他情况岂不是没返回的东西?
    }
}

以下情况就可以不需要else语句:

fun main() {
    val c = true
    val numericValue = when (c) {
        false -> 0
        true -> 1
        // 由于Boolean只具备真和假条件,这里的'else' 就不再强制要求
      	// 这同样适用于比如枚举类等
    }
}

when语句中,遇到以下情况,携带else分支是必须的:

  • when分支中仅有一个Boolean类型、枚举 或 密封,以及用于判断的目标变量是可空的情况(后面会讲解)
  • when分支没有包括该判断目标的所有可能的值。

有时候我们可能希望某些值都属于同一个情况,可以使用逗号将其条件组合成一行:

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

我们也可以使用任意表达式(不仅仅是常量)作为分支条件,比如之前的if-else案例中我们判断学生成绩:

fun main() {
    val score = 10
    val grade = when(score) {
      	//使用in判断目标变量值是否在指定范围内
        in 100..90 -> "优秀"
        in 89..80 -> "良好"
        in 79..70 -> "及格"
        in 69..60 -> "牛逼"
        else -> "不及格"
    }
}

包括我们之后学习的类型判断is表达式、函数调用等,都可以在这里作为分支条件。

循环结构(for)

通过前面的学习,我们了解了如何使用分支语句来根据不同的条件执行不同的代码,我们接着来看第二种重要的流程控制语句:循环语句。

我们在某些时候,可能需要批量执行某些代码:

fun main() {
    println("大烟杆嘴里塞,我只抽第五代")   //把这句话给我打印三遍
    println("大烟杆嘴里塞,我只抽第五代")
    println("大烟杆嘴里塞,我只抽第五代")
}

遇到这种情况,我们由于还没学习循环语句,那么就只能写N次来实现这样的多次执行。但是如果此时要求我们将一句话打印100遍、1000遍、10000遍,那么我们岂不是光CV代码就要搞一下午?

现在,要解决这种问题,我们可以使用for循环语句来多次执行:

for (遍历出来的单个目标变量 in 可遍历目标) 循环体

这里的可遍历目标有很多,比如:

  • 数组
  • 区间
  • 任何实现了运算符重载函数iterator的类

这里我们只学习了区间,我们来看看如何使用,比如我们要打印一段话3遍:

fun main() {
    for (i in 1..3)  //这里直接写入1..3表示1~3这个区间
        println("大烟杆嘴里塞,我只抽第五代:$i")
}

打印结果为:
在这里插入图片描述

可以看到,每一次遍历出来的变量i,其实就是每次遍历的下一个目标,比如这里是1…3的区间,那么得到的依次就是1、2、3这三个结果了,唯一需要注意的是,这里的i是局部的,只在for循环内部可用(包括嵌套的内部)并不是整个main中都可以使用:
在这里插入图片描述

默认情况下,每一轮循环都会向后+1,我们也可以自由控制每一轮增加多少,也就是步长:

fun main() {
    for (i in 1..10 step 2) {
        println(i)
    }
}

这样,打印出来的数据会按照步长进行增长:
在这里插入图片描述

那如果我们需要从10到1倒着进行遍历呢?我们可以将..替换为downTo来使用:

fun main() {
    for (i in 10 downTo 1) {
        println(i)   //这里得到的就是10到1倒着排列的范围了
    }
}

我们可以使用调试来观察每一轮的变化,调试模式跟普通的运行一样,也会执行我们的Java程序,但是我们可以添加断点,也就是说当代码运行到断点位置时,会在这里暂停,我们可以观察当代码执行到这个位置时各个变量的值:
在这里插入图片描述

调试模式在我们后面的学习中非常重要,影响深远,所以说各位小伙伴一定要学会。调试也很简单,我们只需要点击右上角的调试选项即可(图标像一个小虫子一样,因为调试的英文名称是Debug)
在这里插入图片描述

调试开始时,我们可以看到程序在断点位置暂停了:
在这里插入图片描述

此时我们可以观察到当前的变量i的值,也可以直接在下方的调试窗口中查看:
在这里插入图片描述

随着循环的进行,i的值也会逐渐自增。

和之前的if一样,for循环同样支持嵌套使用:

fun main() {
    for (i in 0..2)  //外层循环执行3次
        for (j in 0..2)  //内层循环也执行3次
            println("外层$i,内层$j")
}

上面的代码中,外层循环会执行3轮,而整个循环体又是一个循环语句,那么也就是说,每一轮循环都会执行里面的整个循环,里面的整个循环会执行3,那么总共就会执行3 x 3次,也就是9次打印语句。

我们也可以在循环过程中提前终止或是加速循环的进行,这里我们需要认识两个新的关键字:

for (i in 0..2) {
    if (i == 1) continue  //比如我们希望当i等于1时跳过这一轮,不执行后面的打印
    println("在这么冷的天")
    println("当前i的值为:$i")
}

我们可以使用continue关键字来跳过本轮循环,直接开启下一轮。这里的跳过是指,循环体中,无论后面有没有未执行的代码,一律不执行,比如上面的判断如果成功,那么将执行continue进行跳过,虽然后面还有打印语句,但是不会再去执行了,而是直接结束当前循环,开启下一轮。

在某些情况下,我们可能希望提前结束循环:

fun main() {
    for (i in 0..2) {
        if (i == 1) break //我们希望当i等于1时提前结束
        println("伞兵一号卢本伟准备就绪!")
        println("当前i的值为:$i")
    }
}

我们可以使用break关键字来提前终止整个循环,和上面一样,本轮循环中无论后续还有没有未执行的代码,都不会执行了,而是直接结束整个循环,跳出到循环外部。

虽然使用break和continue关键字能够更方便的控制循环,但是注意在多重循环嵌套下,它只对离它最近的循环生效(就近原则):

fun main() {
    for (i in 1..3) {
        for (j in 1..3) {
            if (i == j) continue  //当i == j时加速循环
            println("$i, $j")
        }
    }
}

这里的continue加速的对象并不是外层的for,而是离它最近的内层for循环,break也是同样的规则:

fun main() {
    for (i in 1..3) {
        for (j in 1..3) {
            if (i == j) break //当i == j时终止循环
            println("$i, $j")
        }
    }
}

那么,要是我们就是想要终止或者是加速外层循环呢?我们可以为循环语句打上标记:

fun main() {
    outer@ for (i in 1..3) {   //在循环语句前,添加 标签@ 来进行标记
        inner@ for (j in 1..3) {
            if (i == j) break@outer  //break后紧跟要结束的循环标记,当i == j时终止外层循环
            println("$i, $j")
        }
    }
}

关于for语句的更多用法,我们会在后续的学习中继续认识。

循环结构(while)

前面我们介绍了for循环语句,我们接着来看第二种while循环,for循环要求我们给一个可遍历的目标,而while相当于是一个简化版本,它只需要我们填写循环的维持条件即可,比如:

while(循环条件) 循环体;

相比for循环,while循环更多的用在不明确具体的结束时机的情况下,而for循环更多用于明确知道循环的情况,比如我们现在明确要进行循环10次,此时用for循环会更加合适一些,又比如我们现在只知道当i大于10时需要结束循环,但是i在循环多少次之后才不满足循环条件我们并不知道,此时使用while就比较合适了。

fun main() {
    var i = 100 //比如现在我们想看看i不断除以2得到的结果会是什么,但是循环次数我们并不明确

    while (i > 0) {   //现在唯一知道的是循环条件,只要大于0那么就可以继续除
        println(i)
        i /= 2 //每次循环都除以2
    }
}

上面的这种情况就非常适合使用while循环。

和for循环一样,while也支持使用break和continue来进行循环的控制,以及嵌套使用:

fun main() {
    var i = 100
    while (i > 0) {
        if (i < 10) break
        println(i)
        i /= 2
    }
}

我们也可以反转循环判断的时机,可以先执行循环内容,然后再做循环条件判断,这里要用到do-while语句:

fun main() {
    var i = 0 //比如现在我们想看看i不断除以2得到的结果会是什么,但是循环次数我们并不明确

    do {  //无论满不满足循环条件,先执行循环体里面的内容
        println("Hello World!")
        i++
    } while (i < 10) //再做判断,如果判断成功,开启下一轮循环,否则结束
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

事件抽取(Event Extraction, EE)

一、引言 事件抽取&#xff08;Event Extraction, EE&#xff09;是信息抽取领域中的一个重要任务&#xff0c;旨在从非结构化文本中识别和抽取事件相关的信息。事件抽取通常包括识别事件触发词、事件类型以及事件中的参与者、时间、地点等元素&#xff0c;最终将这些信息结构…

【进阶OpenCV】 (4)--图像拼接

文章目录 图像拼接1. 读取图片2. 计算图片特征点及描述符3. 建立暴力匹配器4. 特征匹配5. 透视变换6. 图像拼接 总结 图像拼接 图像拼接是一项将多张有重叠部分的图像&#xff08;这些图像可能是不同时间、不同视角或者不同传感器获得的&#xff09;拼成一幅无缝的全景图或高分…

论文翻译 | Model-tuning Via Prompts Makes NLP Models Adversarially Robust

摘要 近年来&#xff0c;NLP从业者集中于以下实践:(i)导入现成的预训练(掩码)语言模型;(ii)在CLS令牌的隐藏表示(随机初始化权重)上附加多层感知器;(iii)在下游任务(MLP-FT)上微调整个模型。这一过程在标准的NLP基准上产生了巨大的收益&#xff0c;但这些模型仍然很脆弱&#x…

mysql单表查询·3

准备好表 create table product(id int primary key,name varchar(32),price double,category varchar(32) ); # 插入数据 INSERT INTO product(id,name,price,category) VALUES(1,联想,5000,c001); INSERT INTO product(id,name,price,category) VALUES(2,海尔,3000,c001); I…

加密与安全_HOTP一次性密码生成算法

文章目录 HOTP 的基础原理HOTP 的工作流程HOTP 的应用场景HOTP 的安全性安全性增强措施Code生成HOTP可配置项校验HOTP可拓展功能计数器&#xff08;counter&#xff09;计数器在客户端和服务端的作用计数器的同步机制客户端和服务端中的计数器表现服务端如何处理计数器不同步计…

好用的苹果笔推荐!五大高品质王者款!附避坑宝典助你选购无忧!

现在平板和电容笔在一定程度上可以替代传统的笔和纸&#xff0c;很多用户在购置iPad后&#xff0c;急需找到一款好用的电容笔。但由于苹果原装笔的价格太过高昂&#xff0c;让许多人不得不选择平替电容笔&#xff01;下面我就为大家推荐五款高品质的电容笔&#xff0c;并分享几…

单细胞hdWGCNA分析学习和整理

hdWGCNA的分析逻辑是跟bulkRNA数据中的WGCNA基本一样&#xff0c;只是hdWGCNA中多了一步metacell过程&#xff0c;有助于减少无用的信息(单细胞数据有很多零值&#xff0c;会影响分析结果)。 WGCNA的基础信息可见既往推文: https://mp.weixin.qq.com/s/2Q37RcJ1pBy_WO1Es8upIg…

二分查找算法专题(2)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; 优选算法专题 对于二分查找算法不是很了解或者只了解一部分的小伙伴一定要去看下面这篇博客&#xff1a;二分查找算法的介绍与另外一种查找方…

【EcoNAS: Finding Proxies for Economical Neural Architecture Search】读后感

鄙人近日阅读了来自 CVPR2020 的一篇论文, 在这里与大家分享一下读后感, 有些东西可能不一定正确, 还望大家指正. Exploration Study 进化算法是 NAS 中一种常用的搜索算法, 使用进化算法时, 如果将每一个候选网络训练到完全收敛来评估性能的话, 需要耗费大量的资源 (时间, G…

现代身份和访问管理 IAM 如何降低风险

您的公司是否仍在使用 1998 年时的身份管理系统&#xff1f;仅凭用户名和密码就能登录本地网络并访问几乎所有资源吗&#xff1f; 虽然大多数企业已经转向现代身份和访问管理(IAM) 平台&#xff0c;但成千上万的企业和其他组织仍然依赖过时的用户名/密码系统。 如果你看一下传…

Ubuntu18.04配置OpenPCDet并运行demo过程记录

一、概述 因为最近需要配置OpenPCDet&#xff0c;发现在配置过程中存在诸多的问题需要解决&#xff0c;将过程中所遇到的问题进行记录保存。 二、具体配置过程 &#xff08;一&#xff09;参考链接 因为中间遇到了很多问题&#xff0c;参考了很多不少相应的博客进行问题解决。…

【Unity】unity安卓打包参数(个人复习向/有不足之处欢迎指出/侵删)

1.Texture Compression 纹理压缩 设置发布后的纹理压缩格式 Use Player Settings:使用在播放器设置中设置的纹理压缩格式 ETC&#xff1a;使用ETC格式&#xff08;兼容&#xff09; ETC2&#xff1a;使用ETC2格式&#xff08;很多设备不支持&#xff09; ASTC&#xff1a;使用…

使用JavaScript写一个网页端的四则运算器

目录 style(内联样式表部分) body部分 html script 总的代码 网页演示 style(内联样式表部分) <style>body {font-family: Arial, sans-serif;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f0f0f0;}.calculator {…

c++ 指针传参

// // Created by 徐昌真 on 2024/10/4. // #include <iostream>//函数的值传递 void swap(int a, int b){ //只是单纯的改变了函数内部a b的值 在main函数内值并不会改变 因为值存在地址里面 而地址里面的值要通过指针来改变int temp;temp a;a b;b temp; }//函数的址…

Oracle架构之表空间详解

文章目录 1 表空间介绍1.1 简介1.2 表空间分类1.2.1 SYSTEM 表空间1.2.2 SYSAUX 表空间1.2.3 UNDO 表空间1.2.4 USERS 表空间 1.3 表空间字典与本地管理1.3.1 字典管理表空间&#xff08;Dictionary Management Tablespace&#xff0c;DMT&#xff09;1.3.2 本地管理方式的表空…

8647 实现图的存储结构

### 思路 1. 读取输入的顶点个数n和边的条数m。 2. 初始化一个n*n的邻接矩阵&#xff0c;所有元素初始为0。 3. 读取每条边的信息&#xff0c;更新邻接矩阵对应位置为1。 4. 输出邻接矩阵。 ### 伪代码 1. 读取n和m。 2. 初始化n*n的邻接矩阵matrix&#xff0c;所有元素为0。 …

CSS列表和超链接的使用(8个案例+代码+效果图+素材)

目录 1.无序列表ul 案例:定义不同type的li 1.代码 2.效果 2.有序列表ol type 取值 start属性 value 案例:定义不同类型的有序列表 1.代码 2.效果 3.定义列表dl 1.代码 2.效果 4.list-style-type属性 list-style-type的取值 案例:list-type的使用 1.代码 2.效果 5.list-style-im…

关于OJ平台的一个代码小问题 ——

目录 一、关于OJ平台的一个代码小问题 1、将OJ代码复制粘贴到vs上 2、创建测试方法&#xff0c;调用本次要调试的目标方法 3、利用vs调试工具排查代码问题 一、关于OJ平台的一个代码小问题 思考&#xff1a;OJ代码有bug怎么办&#xff1f; 答&#xff1a;VS调试技能用起来 …

G. Gears (2022 ICPC Southeastern Europe Regional Contest. )

G. Gears 思路&#xff1a; 本身这个题并不难&#xff0c;奈何卡了很久后看了题解才做出来&#xff0c;感觉自己好笨。 很容易想到的是&#xff0c;只要确定了一个齿轮的位置&#xff0c;其他齿轮的位置都可以直接推出来。所以当前目标是如何确定第一个齿轮的位置。 令 x [ i …

第2篇:Windows权限维持----应急响应之权限维持篇

关键词&#xff1a;Windows系统后门、权限维持 在获取服务器权限后&#xff0c;通常会用一些后门技术来维持服务器权限&#xff0c;服务器一旦被植入后门&#xff0c;攻击者便如入无人之境。本文将对常见的window服务端自启动后门技术进行解析&#xff0c;知己知彼方能杜绝后门…