【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的一个特色,用户可以自定义中缀函数来进行操作

我们之前学习过的区间中的 ..downTountilin等,其实都是中缀函数,包括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(面向对象)

【Kotlin】初识Kotlin(二)的更多相关文章

  1. 初识Kotlin之变量

    用Java开发了很多年,因为工作的需要学习Kotlin.初识Kotlin时是各种不习惯,觉得这个语言相对于Java而言并不够严谨.随着不断的深入,最终还是逃不过"真香定理".我一直 ...

  2. 【Kotlin】初识Kotlin之面向对象

    [Kotlin]初识Kotlin之面向对象 1.类 在Kotlin中,类用关键字class来定义 如果一个类具有类体,那么需要使用{ }来写类体内容,如果不需要类体,那么只需要定义类名就可以了 // ...

  3. 初识Kotlin之函数

    本章通过介绍Kotlin的基本函数,默认参数函数,参数不定长函数,尾递归函数,高阶函数,Lamdba表达式.来对Kotlin函数做进一步了解.将上一篇的Kotlin变量的知识得以运用.Kotlin变量 ...

  4. 初识JavaScript(二)

    初识JavaScript(二) 我从上一篇<初识JavaScript(一)>知道和认识JavaScript的词法结构,也开始慢慢接触到了JavaScript的使用方法,是必须按照JavaS ...

  5. Kotlin基础(二)函数的定义与调用

    函数的定义与调用 一.预备知识:在Kotlin中创建集合 fun main(args: Array<String>) { //Kotlin中定义各自集合 val ,,,) val list ...

  6. 初识Kotlin之集合

    Kotlin的集合是让我为之心动的地方,丰富的高阶函数帮助我们高效开发.今天介绍Kotlin的基础集合用法.获取集合元素的函数.过滤元素的函数.元素排序的函数.元素统计的函数.集合元素映射的函数.集合 ...

  7. 第一行Kotlin系列(二)Intent隐式显式跳转及向下传值

    1.Intent显式跳转页面 val button5 = findViewById<Button>(R.id.mButton5) button5.setOnClickListener { ...

  8. 让你的代码量减少3倍!使用kotlin开发Android(二) --秘笈!扩展函数

    本文承接上一篇文章:让你的代码量减少3倍!使用kotlin开发Android(一) 创建Kotlin工程 本文同步自博主的私人博客wing的地方酒馆 上一节说到,kotlin可以省去getter,se ...

  9. kotlin学习(二)——类

    Kotlin中的类遵循一个简单的结构.尽管与Java有一点细微的差别.你可以使用try.kotlinlang.org在不需要一个真正的项目和不需要部署到机器的前提下来测试一些简单的代码范例. 1. 怎 ...

随机推荐

  1. 最新RabbitMQ安装指南2021.07

    一.RabbitMQ入门及安装 1.入门及安装 01 概述 简单概述: RabbitMQ是一个开源的遵循 AMQP协议实现的基于 Erlang语言编写,支持多种客户端(语言),用于在分布式系统中存储消 ...

  2. 《剑指offer》面试题56 - II. 数组中数字出现的次数 II

    问题描述 在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次.请找出那个只出现一次的数字. 示例 1: 输入:nums = [3,4,3,3] 输出:4 示例 2: 输入:nums ...

  3. 12.25 补充总结-jsp标签

    注:标签引用时,需在jsp 头部添加如下语句 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c ...

  4. cv::copyMakeBorder()中用0值对齐矩阵,方便后续加速傅里叶变换

    int M = cv::getOptimalDFTSize(mul_result.rows); // 获得最佳DFT尺寸,为2的次方 int N = cv::getOptimalDFTSize(mul ...

  5. 【记录一个问题】android下的ucontext协程,因为使用栈上的对象,导致cv::Mat被莫名析构

    工作的流程是这样:某个协程在栈上创建task对象,在task对象内有需要返回的cv::Mat. 然后把task放到另一个线程上去执行,然后切换到别的协程,等到工作线程执行完task后,再唤醒协程. 这 ...

  6. Web安全防护(二)

    点击劫持 点击劫持,也称UI覆盖攻击 1.1 iframe覆盖攻击 黑客创建一个网页,用iframe包含了目标网站,并且把它隐藏起来.做一个伪装的页面或图片盖上去,且按钮与目标网站一致,诱导用户去点击 ...

  7. C#运算符重载---逐步地分析与理解

    1.什么是运算符重载 定义:(百科定义)就是把已经定义的.有一定功能的操作符进行重新定义,来完成更为细致具体的运算等功能.操作符重载可以将概括性的抽象操作符具体化,便于外部调用而无需知晓内部具体运算过 ...

  8. Log4j2日志技术总结

    前言 现在流行是SLF4j和Log4j2组合的日志技术,但为了日志技术归类,故前因后果都将做一下介绍. 市场上流行的日志框架 JUL java util logging Java开发团队开发,Jdk原 ...

  9. Maven仓库的目录结构

    _remote.repositories文件 本地库中的包都有一个_remote.repositories文件,示例: #NOTE: This is an Aether internal implem ...

  10. <select><option></option></select> 操作

    转载请注明来源:https://www.cnblogs.com/hookjc/ function FlySwapSelect(s1,s2,myvars,calldbclick){ var mSel1= ...