发布于2022年11月4日3年前 【Kotlin】初识Kotlin(二) 1、Kotlin的流程控制 流程控制是一门语言中最重要的部分之一,从最经典的if...else...,到之后的switch,再到循环控制的for循环和while循环,都是在开发中离不开的。 之前在第一篇博文中提到了Kotlin中的for循环和foreach循环,从中可以看出Kotlin在这些流程处理中下了很大一片功夫,也进行了人性化的创新。 接下来我们就从最经典的if ... else ...来讲起! 1. if表达式 说起if,我们已经非常熟悉了。也许它的执行效率却在某些情况下不是最高的,但是它的实用性绝对是最高的! 最传统的用法咱们不讲,咱们讲讲Kotlin中if创新的用法: if表达式当作三元运算符 if块 (1) 代替三元运算符 Kotlin在操作符中,没有三元操作符case ? A : B,但是我们仍然有替代方案,那就是Kotlin中的if (case) A else B。在缺少三元操作符这一块上,Kotlin使用类似了python的方法,使用if ... else ...来代替! fun main() { val flag = 1 == 2 println(if (flag) "true" else "false") } 反正只要是三元运算符可以做的,if表达式可以做到! (2) if块 块,就是代码块,也就是说if后面可以带上代码块,这是Java所做不到的 我们举一个例子 fun main() { val a = -114 val b = -1919 val max = if (a > b) { println("$a is larger than $b.") println("max variable holds value of a.") a } else { println("$b is larger than $a.") println("max variable holds value of b.") b } println("max = $max") } /* -114 is larger than -1919. max variable holds value of a. max = -114 进程已结束,退出代码0 */ 我们发现,{}内中的内容我们也执行了。注意的一点是,代码块中最后一行是返回值,这也是lambda的特性之一! 这里不得不提一句,每次在Java中写三元运算符的时候,总想写一些骚操作,比如在三元运算符的时候执行方法,但是偏篇不行,非得写成4行的if...else...,但是在Kotlin中,方法、代码块都能在if ... else ...中实行了,实在是太方便了! 上述的代码可以转换成这样的: fun main() { val a = -114 val b = -1919 val max = if (a > b) shutA(a,b) else shutB(a,b) println("max = $max") } fun shutA(a: Int, b: Int): Int { println("$a is larger than $b.") println("max variable holds value of a.") return a } fun shutB(a: Int, b: Int): Int { println("$b is larger than $a.") println("max variable holds value of b.") return b } 同样的,if块也可以使用if ... else if ... else ...的方式 2. when表达式 这个可是Kotlin独有的表达式,可以说是switch的增强版,非常的实用! 在上一篇博文讲解for循环的例子中,我们就简单的使用了when表达式,现在我们来具体分析一下 我们举一个简单的when表达式的例子: fun main() { println("输入符号") val result = when (val operator = readLine()) { "+" -> 0 "-" -> 1 "*" -> 2 "/" -> 3 else -> -1 } println("selected index = $result") } 我们使用when来进行选择,()内是选择的一个对象,这里选择的是我们在控制台写入的一行字符串 对应我们在控制台写入的不同的情况,会给reslut变量赋不同的值 再看一种不用when赋值的情况 fun main() { val a = 12 val b = 5 println("输入符号 +, -, * , /") when (val operator = readLine()) { "+" -> println("$a + $b = ${a + b}") "-" -> println("$a - $b = ${a - b}") "*" -> println("$a * $b = ${a * b}") "/" -> println("$a / $b = ${a / b}") else -> println("$operator 不是有效符号") } } 这种场景就很类似于switch了,只不过 -> 之后可以执行{}区域内的代码块 还有多情况的when选择,也可以使用,隔开表示多种情况 fun main() { val n = -1 when (n) { 1, 2, 3 -> println("n is a positive integer less than 4.") 0 -> println("n is zero") -1, -2 -> println("n is a negative integer greater than 3.") } } 我们还可以配合is关键字和!is来判断是我们选择的对象是否是某个类 fun main() { val mutableListOf = mutableListOf("String", false, 1, 'c') mutableListOf.forEach() { when(it) { is String -> println("String") is Boolean -> println("Boolean") is Char -> println("Char") else -> println("Int") } } } 当然,我们还可以判断区间!在刚开始学编程的时候,你肯定做过一种题目,就是考试成绩的打印,多少分到多少分是什么挡位,频繁的if...else...写腻了,为何不试试愉快的when呢? fun main() { println("请输入你的分数") when(readLine()?.toInt()) { in 0 until 60 -> println("不及格") in 60 until 80 -> println("良好") in 80 .. 100 -> println("优秀") else -> println("请输入正确的成绩") } } 还有最后一种when无参的情况,也就是when 中的参数可能并非满足我们的需求,我们可以选择省略该参数 fun main() { val tmp = "1" val tmp2 = "2" when { tmp == "1" -> println(tmp) tmp2 == "2" -> println(tmp2) } } 这样会打印出"1",到这里when就终止啦,我们可以通过这样的使用方式来进行多个选择 3. break和continue 首先因为while循环和大多数语言没有太大的区别,所以这里就不介绍了,直接介绍break和continue break和continue是配合for循环、while循环使用的控制循环执行的两个关键字。之所以我要讲这两个关键字,是因为在Kotlin中有了更强大的使用方式 最基本的使用方式我这里就不多说了,我直接举一个Kotlin中特有的例子 fun main(args: Array<String>) { first@ for (i in 1..4) { second@ for (j in 1..2) { println("i = $i; j = $j") if (i == 2) break@first } } } /* i = 1; j = 1 i = 1; j = 2 i = 2; j = 1 */ 看着代码,你应该理解了break@one的含义,没错,中断用one@标注的这一层循环! 瞬间对Kotlin的处理方式佩服的五体投地。在以往要处理各个嵌套循环,因为要控制条件,往往不能这么写,但是Kotlin支持给for循环、while循环添加@标注,然后对标注的循环体进行break和continue,实在是太香了! 那么带标签的continue也是一样的使用方式: fun main(args: Array<String>) { here@ for (i in 1..5) { for (j in 1..4) { if (i == 3 || j == 2) continue@here println("i = $i; j = $j") } } } /* i = 1; j = 1 i = 2; j = 1 i = 4; j = 1 i = 5; j = 1 */ 2、Kotlin的函数 首先说明一点,Kotlin的语言逻辑和C++类似,既可以面向对象,也可以面向过程。 我们这里提及的函数,仅仅是单方面满足处理需求的,并不是与对象相关的方法 不在对象中的,被称之为函数 这是 Kotlin 标准库的链接,可以参阅! 1. 普通函数 Kotlin中变量的定义在第一篇博文中就讲了,那么如果函数中存在参数,一样的就在()中写入传入的参数变量就可以了 值得注意的是Kotlin中是值传递,而非引用传递,所以更改传递进来的局部变量参数,并不会改变函数之外传入参数的真实值 例如,一个最简单的加法函数的编写: fun add(a:Int,b:Int) : Int { return a+b } 当然,如果函数返回单个表达式,则可以省略函数主体的花括号{ },并在=符号后指定主体,例如 fun add(a:Int,b:Int) : Int = a+b 当然,再省略一点,可以让Kotlin自动推断返回值类型 fun add(a:Int,b:Int) = a+b 2. 中缀函数 中缀函数算是Kotlin的一个特色,用户可以自定义中缀函数来进行操作 我们之前学习过的区间中的 ..,downTo,until,in等,其实都是中缀函数,包括Map中的to也是中缀函数,之前说是关键字,其实并不准确,准确来说是一个中缀函数 同时,在这里得提到,与Java不同,Kotlin中没有按位运河移位运算符,为了解决这种问题,Kotlin官方使用了中缀函数来完成 shl - 符号左移 shr - 符号右移 ushr - 无符号右移 and - 按位和 or - 按位或 xor - 按位异或 inv - 按位反转 那么如何创建一个带有中缀符号的函数呢?有下面几个限制 只有一个参数 在方法前必须加infix关键字 必须是成员方法或者扩展方法 例如我在自己写的一个Student类中,定义一个输出学号的中缀函数callNumber class Student() { infix fun callNumber(number: String) = println("学生的学号为$number") } fun main() { val student = Student() student callNumber "20203199" } /* 学生的学号为20203199 */ 或者我们可以在现有的类中添加中缀函数,例如我在Int类型中添加一个add的中缀函数 infix fun Int.add(tmp:Int) = this+tmp fun main() { println(1 add 2) } /* 3 */ 3. 函数传参 在Kotlin中,函数传参相比Java得到了非常强的优化,用户体验非常的好,在我看来甚至比python还要好。 (1) 默认参数 Kotlin中运行函数在编写的时候就设置默认参数,所谓默认参数就是拥有默认值的参数,例如 fun add(a:Int = 114, b:Int = 1919) :Int { println("first == $a second == $b") return a+b } fun main() { println(add()) } /* first == 114 second == 1919 2033 */ 这种情况就是使用了默认的a = 114 b = 1919的情况 那么如果我们仅仅赋值一个参数呢? fun add(a:Int = 114, b:Int = 1919) :Int { println("first == $a second == $b") return a+b } fun main() { println(add(810)) } /* first == 810 second == 1919 2729 */ 可以发现Kotlin第一个参数是默认赋值给第一个传参的 那么如果我们想给第二个参数b赋值,而不给a赋值呢? fun add(a:Int = 114, b:Int = 1919) :Int { println("first == $a second == $b") return a+b } fun main() { println(add(b=810)) } /* first == 114 second == 810 924 */ 使用指定传参就可以啦! (2) 传入函数(方法) 值得注意的是,Kotlin函数中允许传入函数(方法)这类参数,步骤比Java简单太多了,只需要指定类型为()即可,例如: fun add(a:Int = 114, b:Int = 1919, myMethod : ()->Unit ) :Int { myMethod() println("first == $a second == $b") return a+b } fun main() { val res = add(myMethod = { println("this is test method") }) println(res) } /* this is test method first == 114 second == 1919 2033 */ 这里传递进去的第三个参数就可以是一个方法(函数),myMethod : ()->Unit 的含义是:myMethod 是一个返回值为Unit类型的函数,Unit相当于Java中的void类型 上述代码等同于 fun add(a:Int = 114, b:Int = 1919, myMethod : ()->Unit ) :Int { myMethod() println("first == $a second == $b") return a+b } fun main() { val res = add(myMethod = { testMethod() }) println(res) } fun testMethod() = println("this is test method") 也可以这样写: fun add(a:Int = 114, b:Int = 1919, myMethod : ()->Unit ) :Int { myMethod() println("first == $a second == $b") return a+b } fun main() { val res = add() { println("测试方法") println("你当然可以在这个方法中写很多内容!") } println(res) } 也就是说,如果函数中只有一个函数参数,我们可以在括号内写lambda表达式来表述方法,也可以在括号外写lambda表达式来表示方法。 如果是两个函数传参呢?可以这样写 fun add(a:Int = 114, b:Int = 1919, myMethod : ()->Unit, myMethod2:()->Unit ) :Int { myMethod() myMethod2() println("first == $a second == $b") return a+b } fun main() { val res = add(myMethod = {println("测试1")}, myMethod2 = { println("测试2") }) println(res) } 或者 fun add(a:Int = 114, b:Int = 1919, myMethod : ()->Unit, myMethod2:()->Unit ) :Int { myMethod() myMethod2() println("first == $a second == $b") return a+b } fun main() { val res = add(myMethod = {println("测试1")}) { println("测试2") } println(res) } 这样的话,()外层的lambda表达式默认是最后一个函数参数的表述实现 (3) 动态参数 什么叫做动态参数?也就是可以传递很多同类型的但是值不同的参数,例如下面的append()函数 fun myAppend(vararg ch:Char): String { val res = StringBuffer() ch.forEach { res.append(it) } return res.toString() } fun main() { val myAppend = myAppend('w', 'o', 'o', 'd', 'w', 'h', 'a', 'l', 'e') println(myAppend) } /* woodwhale */ 这里的ch这个参数是不定长的,因为我们使用了vararg修饰 3、Kotlin的更多内容 由于篇幅限制,本篇仅仅讲述了Kotlin中的流程控制和函数的部分内容,之后会学习Kotlin的OOP(面向对象)!
创建帐户或登录后发表意见