Kotlin之控制语句和表达式

原文链接 Kotlin Controls and Expressions

有结果返回的是表达式,没有返回的称之为语句,语句最大的问题是它没有返回值,那么想要保存结果就必然会产生副作用,比如改变变量。很多时候这是不够方便的,并且在多线程条件下,这甚至是不安全的。Kotlin中,为了加强线程安全性和方便并发和异步,因此绝大多数语句都是表达式。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分支表达式

Kotlin中没有三元条件符(a > b ? a : b),但它的条件分支都是表达式,可以直接放在赋值符的右边,或者用在return语句中。

if表达式

它是一个两个分支的表达式,是有返回值的:

val maxV = if (a > b) a else b

当然了,把它当作常规的语句来使用也是没有问题的:

var max: Int
if (a > b) {max = a
} else {max = b
}

when表达式

当超过2个分支时,if就不能用了,这时可以用when表达式,它支持多个分支,类似于其他语言中的switch:

when (x) {1 -> println("it is 1")2 -> println("it is 2")else -> {println("it is neight 1 nor 2")}
}

需要注意的是,每一行是一个条件,并不是单单指参数与其相等,比如:

when (x) {in 1..5 -> println("Less than 5 bigger than 1")x.isEven() -> println("it is even")else -> println("It is neither even or less than 5")
}

当然,最重要的是when是一个表达式,可以直接用在赋值符的右边,或者当参数传,或者用在return中

fun Request.getBody() =when (val response = executeRequest()) {is Success -> response.bodyis HttpError -> throw HttpException(response.status)}

这里的when就是函数的返回值,可以看到when是一个表达式,它会返回一个值,这个值直接作为函数的返回值

从这几个示例可以看出when表达式相当强大比其他语言的switch要强大许多,并且可以直接当作返回值,当需要超过2个条件分支时就可以使用when表达式。

循环语句

循环是语句,与其他语言也差不多。

while loop

while (x < 10) {println(x)x++
}

屁股向后式do-while loop

do {x = poll()
} while (x < 10)

强大的for loop

这个是最强大,也是最常用的循环语句遍历数组,集合和固定步长时的首选。

for (item in collection) print(item)

这里的collection可以是数组和集合(列表和Set)。严格来说只要collection类型实现了iterator()和next(),就可以在for loop中使用。

for加上range,可以非常强大:

for (i in 1..10) // = for (int i = 1; i <= 10; i++)
for (i in 0 until 10) // = for (int i = 0; i < 10; i++)
for (i in 9 downTo 0) // = for (int i = 9; i >= 0; i--)
for (i in 0 until 10 step 2) // = for (int i = 0; i < 10; i += 2)

如果是数组或者列表,但又必须要用索引,也可以直接来:

for (i in array.indices) {println(array[i]) // 'i' is the index
}

其实有更好的方式:

for ((index, value) in array.withIndex()) {println("the element at $index is $value")
}

其实吧,Kotlin是多范式编程语言,天生支持函数式编程,多数情况下不建议直接上for loop,而是用函数式方式的forEach,数组和集合都支持forEach的:

array.forEach { println(it) }

终止语句

当想提前退出函数的执行,或者循环时,就需要用到终止语句,有三种return, break和continue

return终止函数执行

这个都比较熟悉,常规的用法都是一样的,可以提前退出函数:

fun plot(x: Int) {if (x < 1) {return -1}...return y
}

但当有嵌套的lambda时,如不特别指定,return会退出外层的函数,而不是像想当然的退出lambda,比如:

fun foo() {listOf(1, 2, 3, 4, 5).forEach {if (it == 3) return // non-local return directly to the caller of foo()print(it)}println("this point is unreachable")
}

这个不是终止lambda的执行,而是直接退出函数foo的执行。如果想解决呢,即也退出遍历的lambda有三种方案:

  • 使用标签
fun foo() {listOf(1, 2, 3, 4, 5).forEach lit@{if (it == 3) return@lit // local return to the caller of the lambda - the forEach loopprint(it)}print(" done with explicit label")
}
  • 使用隐式标签,也即遍历的方法当作标签
fun foo() {listOf(1, 2, 3, 4, 5).forEach {if (it == 3) return@forEach // local return to the caller of the lambda - the forEach loopprint(it)}print(" done with implicit label")
}
  • 使用匿名函数而不是lambda,匿名函数与常规函数体效力一样,所以return只在函数体内生效
fun foo() {listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {if (value == 3) return  // local return to the caller of the anonymous function - the forEach loopprint(value)})print(" done with anonymous function")
}

这三种方式,如果非要使用,建议使用方式二,用自带的隐式label,因为比较方便,可读性也不差。

但,非常不建议如此使用return语句,这本是应该避免的问题,lambda多半是用在函数式遍历和处理,在lambda里面提加return本就是非常奇怪的事情。因为如果某些条件不满足,想不执行此lambda,应该用filter啊,而不是笨拙的非要在lambda中去终止:

fun foo() {listOf(1, 2, 3, 4, 5).filter(i -> i != 3).forEach { println(it) }print("You can do whatever you like here.")
}

循环的终止

break终止当前循环,continue则是跳过当前循环的当前步骤,直接跳到下一次迭代。这两个的常规使用与其他语言是一样的。

但对于break,一般来说有一个痛点,就是当有循环嵌套时,break只能终止一层,如果想终止所有循环时,只能再手动的加条件去判断,然后再一层一层的break,比如:

for (i in 0 until 10) {var found = falsefor (j in i until 10) {if (array[i] + array[j] == target) {found = truebreak // only break inner for loop}}if (found) {break // this break outer for loop}
}

这多少有点笨拙和丑陋,Kotlin有更优雅的解决方式,就是引入了标签label,可以给循环加上标签,在break时可以指定标签,同样是上面的情况,可以这样做:

loop@ for (i in 0 until 10) {for (j in i until 10) {if (array[i] + array[j] == target) {break @loop // break all loops easily}}
}

其实吧,这玩意儿跟当年的goto是一样的,虽然可行,但不建议多使用标签多了以后会让程序的执行更加的混乱,试想假如在层层循环中break错了某个标签,调试的难度是相当大的。更多的时候需要仔细想想有没有更好的遍历方式,而不是靠标签来救命。

原创不易,打赏点赞在看收藏分享 总要有一个吧

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件外包开发的开发文档

软件开发文档是一个重要的工具&#xff0c;用于记录和传达项目信息&#xff0c;帮助开发团队和利益相关者理解项目的各个方面。以下是一般性的软件开发文档编写格式&#xff0c;不同组织和项目可能有所不同&#xff0c;但这些通用准则可以帮助确保文档的清晰性和易读性&#xf…

uni-app微信小程序如何开发蓝牙功能

一. 前言。 蓝牙功能在我们日常软件中的使用率还是蛮高的----譬如各类共享单车/电单车。正因此&#xff0c;我们开发中接触蓝牙功能也是日渐增长。对于很多从未开发过蓝牙功能的童鞋来说&#xff0c;当PM小姐姐扔过来一个蓝牙协议要你接入时&#xff0c;简直一头雾水&#xff…

算法:穷举,暴搜,深搜,回溯,剪枝

文章目录 算法基本思路例题全排列子集全排列II电话号码和字母组合括号生成组合目标和组合总和优美的排列N皇后有效的数独解数独单词搜索黄金矿工不同路径III 总结 算法基本思路 穷举–枚举 画出决策树设计代码 在设计代码的过程中&#xff0c;重点要关心到全局变量&#xff…

一分钟搞懂什么是this指针(未涉及静态成员和函数)

前言 我们在学习类的过程中&#xff0c;一定听说过this指针&#xff0c;但是并不知道它跟谁相似&#xff0c;又有什么用途&#xff0c;所以接下来&#xff0c;让我们一起去学习this指针吧&#xff01; 一、this指针的引入 我们先来看下面两段代码&#xff0c;它们输出的是什么&…

IDEA 2022创建Spring Boot项目

首先点击New Project 接下来&#xff1a; (1). 我们点击Spring Initializr来创建。 (2). 填写项目名称 (3). 选择路径 (4). 选择JDK------这里笔者选用jdk17。 (5). java选择对应版本即可。 (6). 其余选项如无特殊需求保持默认即可。 然后点击Next。 稍等一会&#xff0c…

【python后端】- 初识Django框架

Django入门 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0c;大家一起学习成长&#xff01; 文章目录 Django入门…

Programming Abstractions in C阅读笔记:p196

《Programming Abstractions in C》学习第63天&#xff0c;p196总结。涉及到编程之外的知识&#xff0c;依然是读起来很费劲&#xff0c;需要了解作者在书中提到的人物(Edouard Lucas)、地点(Benares)、神话传说(Brahma)等等。虽然深知自己做不到对人文知识&#xff0c;历史知识…

从0到0.01入门React | 009.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

19 - 如何用协程来优化多线程业务?

近几年&#xff0c;国内很多互联网公司开始使用或转型 Go 语言&#xff0c;其中一个很重要的原因就是 Go 语言优越的性能表现&#xff0c;而这个优势与 Go 实现的轻量级线程 Goroutines&#xff08;协程 Coroutine&#xff09;不无关系。那么 Go 协程的实现与 Java 线程的实现有…

vue离线地图(瓦片)

最近公司要弄一个这样的离线地图&#xff0c;要求在图上打点画线之类的。折腾了几天&#xff0c;学习了三种方式&#xff1a; 1.拿到各省市区的经纬度json&#xff0c;通过echarts来制作&#xff0c;再套一个卫星图的地图背景 2.下载地图瓦片&#xff0c;再通过百度/高德的离线…

OpenGL_Learn11(光照)

目录 1. 光照 2. 环境光照 3. 漫反射光照 4. 代码实战 1. 光照 在OpenGL中主要分以下几个光照类型 环境光照(Ambient Lighting)&#xff1a;即使在黑暗的情况下&#xff0c;世界上通常也仍然有一些光亮&#xff08;月亮、远处的光&#xff09;&#xff0c;所以物体几乎永远不…

mac homebrew.mxcl.php@5.6.plist

今天启动php5.6时 遇到了一个问题 servers % brew services start php5.6 Bootstrap failed: 5: Input/output error Try re-running the command as root for richer errors. Error: Failure while executing; /bin/launchctl bootstrap gui/501 /Users/ssh/Library/LaunchAge…