简介
在此 Codelab 中,您将了解 Kotlin 编程语言的基础知识:数据类型、运算符、变量、控制结构,以及可为 null 的变量与不可为 null 的变量。
您应当已掌握的内容
- 如何在 IntelliJ IDEA 中创建项目
- 如何在 IntelliJ IDEA 中打开并执行 Kotlin REPL(读取-求值-输出循环)中的代码 (Tools > Kotlin > Kotlin REPL)
学习内容
- 如何使用 Kotlin 数据类型、运算符和变量
- 如何使用布尔值和条件
- 可为 null 的变量与不可为 null 的变量之间的区别
- 数组、列表和循环在 Kotlin 中的运作方式
实践内容
- 使用 Kotlin REPL 了解 Kotlin 的基础知识
在此任务中,您将了解 Kotlin 编程语言中的运算符和类型。
第 1 步:探索数值运算符
- 打开 IntelliJ IDEA(如果尚未打开)。
- 如需打开 Kotlin REPL,请依次选择 Tools > Kotlin > Kotlin REPL。
与其他语言一样,Kotlin 使用 +
、-
、*
和 /
表示加法、减法、乘法和除法运算。此外,Kotlin 还支持不同的数字类型,如 Int
、Long
、Double
和 Float
。
- 在 REPL 中输入以下表达式。如需查看结果,请在输入每个表达式后按
Control+Enter
(在 Mac 上,按Command+Enter
)。
1+1 ⇒ res8: kotlin.Int = 2 53-3 ⇒ res9: kotlin.Int = 50 50/10 ⇒ res10: kotlin.Int = 5 1.0/2.0 ⇒ res11: kotlin.Double = 0.5 2.0*3.5 ⇒ res12: kotlin.Double = 7.0
请注意,运算结果会保留运算数的类型,因此 1/2 = 0,但 1.0/2.0 = 0.5。
- 尝试一些使用不同整数和小数组合的表达式。
6*50 ⇒ res13: kotlin.Int = 300 6.0*50.0 ⇒ res14: kotlin.Double = 300.0 6.0*50 ⇒ res15: kotlin.Double = 300.0
- 对数字调用一些方法。Kotlin 将数字保留为基元,但允许您对数字调用方法,就像数字是对象一样。
2.times(3) ⇒ res5: kotlin.Int = 6 3.5.plus(4) ⇒ res8: kotlin.Double = 7.5 2.4.div(2) ⇒ res9: kotlin.Double = 1.2
第 2 步:练习使用类型
利用 Kotlin 无法执行隐式类型转换。因此,您无法直接为长变量赋予短值,也无法为 Long
赋予 Int
。这是因为隐式数字转换是程序中常见的错误来源。您始终可以通过类型转换赋予不同类型的值。
- 如需查看部分可能的类型转换,请在 REPL 中定义
Int
类型的变量。
val i: Int = 6
- 创建一个新变量,然后输入上面显示的变量名称,后跟
.to
。
val b1 = i.to
IntelliJ IDEA 会显示可能的补全列表。这种自动补全功能适用于任何类型的变量和对象。
- 从该列表中选择
toByte()
,然后输出变量。
val b1 = i.toByte()
println(b1)
⇒ 6
- 为不同类型的变量赋予
Byte
值。
val b2: Byte = 1 // OK, literals are checked statically
println(b2)
⇒ 1
val i1: Int = b2
⇒ error: type mismatch: inferred type is Byte but Int was expected
val i2: String = b2
⇒ error: type mismatch: inferred type is Byte but String was expected
val i3: Double = b2
⇒ error: type mismatch: inferred type is Byte but Double was expected
- 对于返回错误的赋值,请尝试改为对它们进行类型转换。
val i4: Int = b2.toInt() // OK!
println(i4)
⇒ 1
val i5: String = b2.toString()
println(i5)
⇒ 1
val i6: Double = b2.toDouble()
println(i6)
⇒ 1.0
- 如需提高长数字常量的可读性,利用 Kotlin 可以对您有意义的方式在数字中添加下划线。请尝试输入不同的数字常量。
val oneMillion = 1_000_000 val socialSecurityNumber = 999_99_9999L val hexBytes = 0xFF_EC_DE_5E val bytes = 0b11010010_01101001_10010100_10010010
第 3 步:了解变量类型的值
Kotlin 支持可更改(可变)和不可更改(不可变)这两种类型的变量,分别使用 var
和 val
指定。使用 val
时,您可以赋值一次。如果您尝试再次赋值,就会收到错误消息。使用 var
时,您可以先赋值,稍后再在程序中更改该值。
- 使用
val
和var
定义变量,然后为其赋予新值。
var fish = 1
fish = 2
val aquarium = 1
aquarium = 2
⇒ error: val cannot be reassigned
您可以先为 fish
赋予一个值,然后再为其赋予一个新值,因为它是使用 var
定义的。尝试为 aquarium
赋予一个新值会出现错误,因为它是使用 val
定义的。
当编译器可以根据上下文推断变量时,系统就会推断您存储在该变量中的类型。如有需要,您可以随时使用冒号表示法明确指定变量的类型。
- 定义一些变量并明确指定变量的类型。
var fish: Int = 12
var lakes: Double = 2.5
您或编译器赋予某种类型后,您便无法更改该类型,或者会收到错误消息。
第 4 步:了解字符串和字符
Kotlin 中的字符串是字符序列。通过使用 "
表示字符串,使用 '
表示单个字符,您可以将 Kotlin 中的字符串定义为类似于其他编程语言中的字符串。您可以使用 +
运算符连接字符串。此外,利用 Kotlin 还可以在字符串字面量中使用字符串模板表达式。这些模板是经求值并连接到字符串字面量中的代码片段。字符串模板以“$”开头,后跟 Kotlin 表达式,称为字符串插值。
- 创建一个字符串模板。
val numberOfFish = 5
val numberOfPlants = 12
"I have $numberOfFish fish" + " and $numberOfPlants plants"
⇒ res20: kotlin.String = I have 5 fish and 12 plants
- 创建一个包含表达式的字符串模板。与在其他语言中一样,该值可以是表达式的结果。使用大括号
{}
定义该表达式。
"I have ${numberOfFish + numberOfPlants} fish and plants"
⇒ res21: kotlin.String = I have 17 fish and plants
在此任务中,您将了解 Kotlin 编程语言中的布尔值和检查条件。与其他语言一样,Kotlin 具有布尔值和布尔运算符,如小于、等于、大于等(<
、==
、>
、!=
、<=
、>=
)。
- 编写
if
/else
语句。
val numberOfFish = 50
val numberOfPlants = 23
if (numberOfFish > numberOfPlants) {
println("Good ratio!")
} else {
println("Unhealthy ratio")
}
⇒ Good ratio!
- 利用 Kotlin 可以轻松定义一系列具有起始端点和终止端点的值,称为范围。在 Kotlin 中创建范围的最简单方法是使用“..”运算符。请尝试在
if
语句中使用范围。在 Kotlin 中,测试的条件也可以使用范围。
val fish = 50
if (fish in 1..100) {
println(fish)
}
⇒ 50
- 编写一个包含多个案例的
if
语句。对于更复杂的条件,请使用逻辑 AND&&
和逻辑 OR||
。与在其他语言中一样,您可以使用else if
包含多个案例。
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!
- 请尝试使用
when
语句。在 Kotlin 中,使用when
语句编写该系列if
/else
语句很方便。when
语句类似于其他语言中的switch
语句。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!
在此任务中,您将了解可为 null 的变量和不可为 null 的变量。涉及 null 的编程错误是无数错误的根源。Kotlin 致力于通过引入不可为 null 的变量来减少错误。
第 1 步:了解是否可为 null 性
默认情况下,变量不能为 null
。
- 声明
Int
并为其赋予null
。
var rocks: Int = null
⇒ error: null can not be a value of a non-null type Int
- 在类型后使用问号运算符
?
指示变量可为 null。声明Int?
并为其赋予null
。
var marbles: Int? = null
当您拥有复杂的数据类型(如列表)时:
- 可以允许列表的元素为 null。
- 可以允许列表为 null,但如果列表不为 null,则其元素不能为 null。
- 可以允许列表或元素为 null。
列表和一些其他复杂的数据类型将在后续任务中介绍。
第 2 步:了解 ? 和 ?: 运算符
您可以使用 ?
运算符测试 null
,这样可免于编写多个 if
/else
语句。
- 以更长的方式编写某些代码,以检查
fishFoodTreats
变量是否不为null
。然后,递减该变量。
var fishFoodTreats = 6
if (fishFoodTreats != null) {
fishFoodTreats = fishFoodTreats.dec()
}
- 现在,让我们看看 Kotlin 的编写方法,即使用
?
运算符。
var fishFoodTreats = 6
fishFoodTreats = fishFoodTreats?.dec()
- 此外,您也可以使用
?:
运算符链接 null 测试。看看下面这个示例:
fishFoodTreats = fishFoodTreats?.dec() ?: 0
上面的示例是“如果 fishFoodTreats
不为 null
,则递减并使用该变量;否则,使用 ?:
后的值,即 0”的简写形式。如果 fishFoodTreats
为 null
,系统会终止求值,并且不会调用 dec()
方法。
关于 null 指针的要点
如果您确实喜欢 NullPointerExceptions
,在 Kotlin 中,您可以保留它们。非 null 断言运算符 !!
(!!) 会将任何值转换为非 null 类型,并在值为 null
时抛出异常。
val len = s!!.length // throws NullPointerException if s is null
在此任务中,您将了解数组和列表,并了解使用 Kotlin 编程语言创建循环的不同方法。
第 1 步:创建列表
列表是 Kotlin 中的一种基本类型,类似于其他语言中的列表。
- 使用
listOf
声明一个列表并输出该列表。此列表无法更改。
val school = listOf("mackerel", "trout", "halibut")
println(school)
⇒ [mackerel, trout, halibut]
- 使用
mutableListOf
声明一个可以更改的列表。移除项。
val myList = mutableListOf("tuna", "salmon", "shark")
myList.remove("shark")
⇒ res36: kotlin.Boolean = true
remove()
方法会在成功移除传递的项后返回 true
。
第 2 步:创建数组
与其他语言一样,Kotlin 具有数组。在 Kotlin 中,列表具有可变版本和不可变版本,与之不同,Array
没有可变版本。数组一经创建,其大小便固定不变。除非复制到新数组中,否则无法添加或移除元素。
使用 val
和 var
的规则与数组和列表相同。
- 使用
arrayOf
声明一个字符串数组。使用java.util.Arrays.toString()
数组实用程序进行输出。
val school = arrayOf("shark", "salmon", "minnow")
println(java.util.Arrays.toString(school))
⇒ [shark, salmon, minnow]
- 使用
arrayOf
声明的数组的类型与元素不相关,因此您可以使用混合类型,这会很有帮助。声明具有不同类型的数组。
val mix = arrayOf("fish", 2)
- 此外,您还可以为所有元素声明一种类型的数组。使用
intArrayOf()
声明一个整数数组。对于其他类型的数组,存在相应的构建器或实例化函数。
val numbers = intArrayOf(1,2,3)
- 使用
+
运算符组合两个数组。
val numbers = intArrayOf(1,2,3)
val numbers3 = intArrayOf(4,5,6)
val foo2 = numbers3 + numbers
println(foo2[5])
=> 3
- 尝试嵌套数组和列表的不同组合。与在其他语言中一样,您可以嵌套数组和列表。换句话说,当您将一个数组放入另一个数组时,您将得到一系列数组,而不是这两个数组内容的扁平化数组。此外,数组的元素可以是列表,而列表的元素可以是数组。
val numbers = intArrayOf(1, 2, 3)
val oceans = listOf("Atlantic", "Pacific")
val oddList = listOf(numbers, oceans, "salmon")
println(oddList)
⇒ [[I@89178b4, [Atlantic, Pacific], salmon]
第一个元素 numbers
是 Array
。如果您不使用数组实用程序输出它,Kotlin 会输出地址而不是数组内容。
- Kotlin 的一个优点是,您可以使用代码初始化数组,而不是将数组初始化为 0。不妨试试下面这个示例:
val array = Array (5) { it * 2 }
println(java.util.Arrays.toString(array))
⇒ [0, 2, 4, 6, 8]
初始化代码使用大括号 {}
括起来。在该代码中,it
表示以 0 开头的数组索引。
第 3 步:创建循环
创建列表和数组后,您现在可以按照预期的方式循环遍历元素。
- 创建一个数组。使用
for
循环可遍历数组并输出元素。
val school = arrayOf("shark", "salmon", "minnow")
for (element in school) {
print(element + " ")
}
⇒ shark salmon minnow
- 在 Kotlin 中,您可以同时循环遍历元素和索引。不妨试试下面这个示例:
for ((index, element) in school.withIndex()) {
println("Item at $index is $element\n")
}
⇒ Item at 0 is shark Item at 1 is salmon Item at 2 is minnow
- 尝试不同的步长和范围。您可以指定数字范围或按字母顺序指定字符范围。与在其他语言中一样,不一定要采用步长为 1 的递增范围。您可以通过
downTo
采用递减范围。
for (i in 1..5) print(i)
⇒ 12345
for (i in 5 downTo 1) print(i)
⇒ 54321
for (i in 3..6 step 2) print(i)
⇒ 35
for (i in 'd'..'g') print (i)
⇒ defg
- 尝试一些循环。与其他语言一样,Kotlin 具有
while
循环、do...while
循环以及++
和--
运算符。此外,Kotlin 还具有repeat
循环。
var bubbles = 0
while (bubbles < 50) {
bubbles++
}
println("$bubbles bubbles in the water\n")
do {
bubbles--
} while (bubbles > 50)
println("$bubbles bubbles in the water\n")
repeat(2) {
println("A fish is swimming")
}
⇒ 50 bubbles in the water 49 bubbles in the water A fish is swimmingA fish is swimming
Kotlin 在运算符、列表、循环等基础知识方面与其他语言非常相似,但存在一些显著区别。
在 Kotlin 中,以下功能与您在其他语言中习惯使用的功能可能会有所不同:
- Kotlin 类型无法隐式转换,请使用类型转换。
- 使用
val
声明的变量只能赋值一次。 - 默认情况下,Kotlin 变量不可为 null。使用
?
使变量可为 null。 - 利用 Kotlin 可以在
for
循环中同时循环遍历数组的索引和元素。
以下 Kotlin 编程结构与其他语言的编程结构类似:
- 数组和列表可以是单一类型,也可以是混合类型。
- 数组和列表可以进行嵌套。
- 您可以使用
for
、while
、do
/while
和repeat
创建循环。 when
语句是 Kotlin 版本的switch
语句,但when
更灵活。