Kotlin Bootcamp 自学(2):Kotlin基础
目录
Kotlin Bootcamp 自学(2):Kotlin基础
前言
运算符与数据类型 (Operators and Types)
数值类型(Numerical Type)
练习使用数据类型
字符串(String)
比较条件和布尔值(Boolean)
比较符号
if...else...
关于空值(Nullability)
关于array, list, 和loop
List
Array
循环loop
此系列文章是博主在通过Kotlin官方的Kotlin Bootcamp for Programmers学习时记录的随笔。
博主之前接触过的编程语言主要有Python, C++, PHP,之前也有使用过Java的Springboot架构来编写一些项目内容。最近因为业务需要,需要接触安卓平台的开发,遂学习Kotlin。
该教程是基于IntelliJ IDEA为编译器的Kotlin教程。
前言
在上一篇文章Kotlin Bootcamp 自学(1):Hello Kotlin中,我们介绍了什么是Kotlin,如何安装IntelliJ IDEA和JDK,并且用Kotlin运行HelloWorld程序。本篇文章将着重介绍一些基础的Kotlin知识。
运算符与数据类型 (Operators and Types)
数值类型(Numerical Type)
同其他编程语言一样,Kotlin使用 +, -, *, / 来进行加、减、乘、除。
试着在REPL中分别执行以下每一行代码:
1+1 4-3 2*3 6/3 1.0/2.0 2.0*3.5 2*3.5
输出结果如下:
1+1 res0: kotlin.Int = 2 4-3 res1: kotlin.Int = 1 2*3 res2: kotlin.Int = 6 6/3 res3: kotlin.Int = 2 1.0/2.0 res4: kotlin.Double = 0.5 2.0*3.5 res5: kotlin.Double = 7.0 2*3.5 res6: kotlin.Double = 7.0
可以看到,Kotlin在数值类型运算中和Python时不同的。Python会使用/和//来区分非整除和整除,Kotlin则是继承了Java的特点,所有除法都是用“/”。刚刚从Python换到Kotlin的时候比较容易犯的错误如下:
#Python中"/"运算符的使用 7/2 3.5
//Kotlin中"/"运算符的使用 7/2 res10: kotlin.Int = 3
相对于Kotlin来说,Python对数值类数据的类型管理相对宽松。如果习惯了Python中的宽松用法,不用明确的数据类型声明,在Kotlin中很容易出现算术上的错误。
除了用+-*/进行符号运算,Kotlin还可以调用类方法来实现符号运算:
//plus()加法 3.5.plus(4) res11: kotlin.Double = 7.5 //div()除法 7.5.div(1.5) res12: kotlin.Double = 5.0 //minus()减法 2.4.minus(1.1) res13: kotlin.Double = 1.2999999999999998 //times()乘法 3.2.times(4) res14: kotlin.Double = 12.8
在这里,Kotlin相当于将数字封装成了一个Object(如:2.4是一个Double类的Object),并调用了对应类的运算方法来进行运算。这种方法称为boxing(装箱?)。
虽然boxing是一种可行的运算方式,但是官方不建议这种方法的使用。原因也很简单:被封装成object的数字占用的大小比单纯的数字更大,因此在效率上更低。
练习使用数据类型
在Kotlin中,我们可以使用val或者var来声明变量,比如:
val i = 3 i res16: kotlin.Int = 3
我们也可以在声明变量时声明它的数据类型,比如:
val i: Int = 3 //声明变量i为Int类型 i res16: kotlin.Int = 3
既然可以提前声明变量数据类型,那么赋值时的数据类型就要对应:
这里我们把3.0(double类型)赋给Int类型的变量m,发生了错误
如果我们不能像python一样通过赋值的方式把Double转化成Int,那要怎么操作呢?
Kotlin中数据类型转化的方法为to()
例子如下:
如果我们想把变量i转化成byte类型:
val i: Int = 6 val bi = i.toByte() bi res20: kotlin.Byte = 6
Kotlin还允许在数字中间添加分位符以方便阅读(比如一百万的阿拉伯数字表示是1,000,000):
val oneMillion = 1_000_000 oneMillion res26: kotlin.Int = 1000000 val socialSecurityNumber = 999_99_9999L socialSecurityNumber res28: kotlin.Long = 999999999
在以上的例子中,我们所有的变量声明都是用了val这个关键词(对应英文value,指“值”)。Kotlin还提供了另一种声明变量的方式,即关键词var(对应英文variable,指“变量”)。从两者的含义中可以看出,似乎只有var关键词才对应“变量”这个词。
事实也确实如此。val和var最大的区别就在于:val是不可变变量,var是可变变量。
要如何理解呢?val更像是我们常说的final变量,即一旦声明,就不能二度赋值改变:
(当然,如果是再次输入val oneMillion = 999_999的话,oneMillion的值会变成999999。但是个人认为这样并不是对同一个变量重新赋值,而是删除旧变量后新建了一个变量。在后面关于指针的章节中,会详细解释)
字符串(String)
Kotlin中的字符串和大部分语言的字符串相同,' '表示单个字符(char)," "表示一串字符(String),+可以拼接字符串。字符串模版中调用字符串变量可以使用$字符(类似Javascript)。
比较条件和布尔值(Boolean)
比较符号
Kotlin的比较符号格式与大部分语言相同:>, <, ==, <= >=, !=。
**值得一提的是,Kotlin也支持字符进行比较(如"A" < "a")。具体数值大小请参考ASCII码。
if...else...
if else判断句的格式基本上和Java一样:
val numberOfFish = 50
val numberOfPlants = 23
if (numberOfFish > numberOfPlants) {
println("Good ratio!")
} else {
println("Unhealthy ratio")
}
输出:
Good Ratio!
在if条件中也可以使用range:
val fish = 50
if (fish in 1..100) {
println(fish)
}
输出:
50
在多个逻辑判断时,可以用&&(and),||(or)来表示对应逻辑,同样else if也适用于Kotlin:
if (numberOfFish == 0) {
println("Empty tank")
} else if (numberOfFish < 40) {
println("Got fish!")
} else {
println("That's a lot of fish!")
}
That's a lot of fish! //由于之前定义的numberOfFish是50,所以执行最后一个判断条件
以上的if else判断条件可以由关键字when来代替:
when (numberOfFish) {
0 -> println("Empty tank")
in 1..39 -> println("Got fish!")
else -> println("That's a lot of fish!")
}
That's a lot of fish!
关于空值(Nullability)
在我们的第一章中提到过,Kotlin是一个对空值管理很严谨的语言。那具体体现在哪些方面呢?
首先,我们试着给一个Int变量赋值null:
可以看到报错显示null不能赋给非空类型(non-null type)Int。
如果想要说明某个变量可以被赋值为null,则需要添加"?"
var i: Int? = null //以上代码不报错
如果有复杂的数据结构,比如list:
可以通过规定list可否有空值来限定list中的数据可否为null。如List
关于更多Null Safety的讨论,后续几章会涵盖。同时官方也给出了较为详细的解释:Null safety | Kotlin
如果我们想对某个数据类型的变量进行方法调用,如果该变量值为null,则会出现错误。比如我们之间提到的Int类型:
这里Kotlin提示我们正在用不安全的方法对一个可能为空的变量进行操作。如果想要对一个可能为空的变量进行方法调用,应该同样使用"?"来修饰方法:
图中?.的作用即是告诉系统该变量可能为空。如果为空,则不会执行dec()操作。在dec()后的?:则是常见的三目操作符(the Elvis Operator)。即:如果?:前为可执行操作或True,就执行?:前的操作,否则执行?:后的操作。
值得注意的是,如果想通过以下代码实现上面的三目操作符语句会报错:
var numNull: Int? = null
if (numNull != null) {
numNull = numNull.dec()
}
else{
numNull = 0
}
//error: smart cast to 'Int' is impossible, because 'numNull' is a mutable property that could have been changed by this time
// numNull = numNull.dec()
// ^
报错中指出,这个赋值的操作无法保证正确运行,因为numNull的类型为Int?,所以在第一个非空判断之后,numNull实际上仍有可能会出现值变为null的情况。因此普通的赋值在此处仍有出现NPE(Null Pointer Exception)的可能。numNull.dec()是错误的原因,因此要修改为numNull?.dec()。
**如果,如果,你真的很喜欢看到NPE,你可以使用!!符号来强制将任何数值转化成非空数值类型。
关于array, list, 和loop
List
通过listOf()指令来声明一个不能变动的list。
val school = listOf("Harvard", "PKU", "Tsinghua")
具体不能变动的表现如下:
如果想要使一个list可以变动的话,应使用mutableListOf():
val mutableSchool = mutableListOf("Harvard", "PKU", "Tsinghua")
Array
Array不同于List,它的大小是在声明时就被固定的,因此无论如何Array都不可以被添加或删除元素,除非是将原来的array赋值到一个新的array上。
Array中的元素没有给明确的类型限制,所以可以出现String和Int混用的情况:
当然,你也可以声明规定一个array中的数据类型:
用"+"可以将两个array组合到一起
List和Array可以组合使用:
可以看到,输出结果中出现了一串地址。这里是因为我们没有使用java.util.Arrays.toString来表示Array。List的输出则没有问题。
Kotlin也允许通过直接声明Array大小来新建Array:
循环loop
for循环:
val school = arrayOf("shark", "salmon", "minnow")
for (element in school) {
print(element + " ")
}
输出:
shark salmon minnow
for循环中元素和索引同事输出:
for ((index, element) in school.withIndex()) {
println("Item at $index is $elementn")
}
输出:
var bubbles = 0
//while循环
while (bubbles < 50) {
bubbles++
}
println("$bubbles bubbles in the watern")
//dowhile循环
do {
bubbles--
} while (bubbles > 50)
println("$bubbles bubbles in the watern")
//repeat循环
repeat(2) {
println("A fish is swimming")
}
输出:
50 bubbles in the water 49 bubbles in the water A fish is swimming A fish is swimming
以上便是Kotlin Bootcamp中第二章节的内容。第二章中主要介绍了Kotlin中赋值、空值管理、循环等相关的知识。第三章中,会着重介绍函数相关的内容。
感谢阅读。
2022/6/4
Edward



