Kotlin入门
基本格式
fun main(){
}
2
3
# 变量
val 只读变量
var 可变性变量
# 字符串模板
放在花括号 {} 内,即位于美元符号 $ 之后
val customers = 10
println("There are $customers customers")
// There are 10 customers
println("There are ${customers + 1} customers")
// There are 11 customers
2
3
4
5
6
# 基本类型
// 整型
val year: Int = 2020
val amount: Long = 350_000_000
// 无符号整数
val score: UInt = 100u
// 浮点型
val currentTemp: Float = 24.5f
val price: Double = 19.99
// 布尔值
val isEnabled: Boolean = true
// 字符
val separator: Char = ','
// 字符串
val message: String = "Hello, world!"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 集合
# List
有序的,并且允许包含重复项
// 只读
val readOnlyShapes = listOf("triangle", "square", "circle")
println(readOnlyShapes)
// [triangle, square, circle]
// 可修改
val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
println(shapes)
// [triangle, square, circle]
// casting
// 将可变的列表赋值给一个 List 类型的变量,就可以变成只读
val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
val shapesLocked: List<String> = shapes
// 访问元素
readOnlyShapes[0]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Set
集合是无序的,只存储唯一项
// 只读
val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry")
// 可修改
val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry")
// casting
val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry")
val fruitLocked: Set<String> = fruit
// 访问元素
// 由于集合是无序的,因此无法访问特定索引处的元素。
2
3
4
5
6
7
8
9
10
11
12
# Map
地图将物品存储为键值对的形式。你可以通过键来访问对应的值
// 只读
val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
println(readOnlyJuiceMenu)
// {apple=100, kiwi=190, orange=100}
// 可修改
val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
println(juiceMenu)
// {apple=100, kiwi=190, orange=100}
// casting
val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
val juiceMenuLocked: Map<String, Int> = juiceMenu
// 访问元素
readOnlyJuiceMenu["apple"]
// 添加元素
juiceMenu["coconut"] = 150 // Add key "coconut" with value 150 to the map
println(juiceMenu)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 控制流
如果你需要在 if 和 when 之间做出选择,我们建议使用 when
# if
val d: Int
val check = true
if (check) {
d = 1
} else {
d = 2
}
println(d)
// 1
2
3
4
5
6
7
8
9
10
11
# When
当你的条件表达式包含多个分支时,可以使用 when 。
val obj = "Hello"
when (obj) {
// Checks whether obj equals to "1"
"1" -> println("One")
// Checks whether obj equals to "Hello"
"Hello" -> println("Greeting")
// Default statement
else -> println("Unknown")
}
// 接收参数
val obj = "Hello"
val result = when (obj) {
// If obj equals "1", sets result to "one"
"1" -> "One"
// If obj equals "Hello", sets result to "Greeting"
"Hello" -> "Greeting"
// Sets result to "Unknown" if no previous condition is satisfied
else -> "Unknown"
}
println(result)
// 表达式没有主语
fun main() {
val trafficLightState = "Red" // This can be "Green", "Yellow", or "Red"
val trafficAction = when {
trafficLightState == "Green" -> "Go"
trafficLightState == "Yellow" -> "Slow down"
trafficLightState == "Red" -> "Stop"
else -> "Malfunction"
}
println(trafficAction)
// Stop
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Ranges
使用 .. 运算符
// 1..4 相当于 1, 2, 3, 4
// 声明一个不包括末尾值的范围
// 1..<4 相当于 1, 2, 3
// 以相反的顺序
// 4 downTo 1 相当于 4, 3, 2, 1
2
3
4
5
6
7
8
# 循环
# for
用括号 () 括起来,并使用关键字 in 进行标识
for (number in 1..5) {
// number is the iterator and 1..5 is the range
print(number)
}
// 12345
// 集合也可以
val cakes = listOf("carrot", "cheese", "chocolate")
for (cake in cakes) {
println("Yummy, it's a $cake cake!")
}
// Yummy, it's a carrot cake!
// Yummy, it's a cheese cake!
// Yummy, it's a chocolate cake!
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# While
while
当条件表达式为真时执行某个代码块
var cakesEaten = 0
while (cakesEaten < 3) {
println("Eat a cake")
cakesEaten++
}
// Eat a cake
// Eat a cake
// Eat a cake
2
3
4
5
6
7
8
do-while
先执行代码块,然后再检查条件表达式的结果
var cakesEaten = 0
var cakesBaked = 0
while (cakesEaten < 3) {
println("Eat a cake")
cakesEaten++
}
do {
println("Bake a cake")
cakesBaked++
} while (cakesBaked < cakesEaten)
// Eat a cake
// Eat a cake
// Eat a cake
// Bake a cake
// Bake a cake
// Bake a cake
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 函数
fun sum(x: Int, y: Int): Int {
return x + y
}
fun main() {
println(sum(1, 2))
// 3
}
2
3
4
5
6
7
8
# 参数
fun printMessageWithPrefix(message: String, prefix: String) {
println("[$prefix] $message")
}
fun main() {
// Uses named arguments with swapped parameter order
printMessageWithPrefix(prefix = "Log", message = "Hello")
// [Log] Hello
}
2
3
4
5
6
7
8
9
# 默认参数
第一个被跳过的参数开始,后续的所有参数都需要加上名称。
fun printMessageWithPrefix(message: String, prefix: String = "Info") {
println("[$prefix] $message")
}
fun main() {
// Function called with both parameters
printMessageWithPrefix("Hello", "Log")
// [Log] Hello
// Function called only with message parameter
printMessageWithPrefix("Hello")
// [Info] Hello
printMessageWithPrefix(prefix = "Log", message = "Hello")
// [Log] Hello
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 不返回值的函数
没有返回任何有用的值,那么其返回类型就是 Unit
fun printMessage(message: String) {
println(message)
// `return Unit` or `return` is optional
}
fun main() {
printMessage("Hello")
// Hello
}
2
3
4
5
6
7
8
9
# 单表达式函数
fun sum(x: Int, y: Int): Int {
return x + y
}
fun sum(x: Int, y: Int) = x + y
fun main() {
println(sum(1, 2))
// 3
}
2
3
4
5
6
7
8
9
# Lambda 表达式
fun uppercaseString(text: String): String {
return text.uppercase()
}
fun main() {
println(uppercaseString("hello"))
// HELLO
}
// lambda 表达式
fun main() {
val upperCaseString = { text: String -> text.uppercase() }
println(upperCaseString("hello"))
// HELLO
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
将 lambda 表达式传递给函数
// filter
val numbers = listOf(1, -2, 3, -4, 5, -6)
val positives = numbers.filter ({ x -> x > 0 })
val isNegative = { x: Int -> x < 0 }
val negatives = numbers.filter(isNegative)
println(positives)
// [1, 3, 5]
println(negatives)
// [-2, -4, -6]
// map
// 对集合中的元素进行转换
val numbers = listOf(1, -2, 3, -4, 5, -6)
val doubled = numbers.map { x -> x * 2 }
val isTripled = { x: Int -> x * 3 }
val tripled = numbers.map(isTripled)
println(doubled)
// [2, -4, 6, -8, 10, -12]
println(tripled)
// [3, -6, 9, -12, 15, -18]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 面向对象
# 定义
// 在类名后面加上括号中的 ()
class Contact(val id: Int, var email: String) {
// 在由大括号{}定义的类体内部
val category: String = ""
}
2
3
4
5
建议将属性声明为只读属性(
val),除非在创建类的实例之后还需要对这些属性进行修改
类属性也可以拥有默认值
class Contact(val id: Int, var email: String = "[email protected]") {
val category: String = "work"
}
2
3
# 创建实例
使用构造函数来声明一个类实例
class Contact(val id: Int, var email: String)
fun main() {
// contact 是 Contact 类的实例,id 和 email 是属性。
val contact = Contact(1, "[email protected]")
}
2
3
4
5
6
# 访问属性
实例名称后.该属性的名称
class Contact(val id: Int, var email: String)
fun main() {
val contact = Contact(1, "[email protected]")
println(contact.email)
// [email protected]
// 使用字符串模板
println("Their email address is: ${contact.email}")
}
2
3
4
5
6
7
8
9
10
11
12
# 成员函数
通过成员函数来定义对象的的行为
class Contact(val id: Int, var email: String) {
fun printId() {
println(id)
}
}
fun main() {
val contact = Contact(1, "[email protected]")
// Calls member function printId()
contact.printId()
// 1
}
2
3
4
5
6
7
8
9
10
11
12
# 数据类
data class User(val name: String, val id: Int)
在生成成员函数时,Kotlin 编译器只会使用主构造函数中定义的属性。如果你在数据类的主体中声明了属性,这些属性不会包含在生成的函数的输出结果中
数据类中最实用的预定义成员函数包括
toString()
val user = User("Alex", 1)
// Automatically uses toString() function so that output is easy to read
println(user)
// User(name=Alex, id=1)
2
3
4
5
6
输出一个易于阅读的字符串,其中包含类实例及其属性信息。
equals() or ==
比较同一类中的不同实例。
val user = User("Alex", 1)
val secondUser = User("Alex", 1)
val thirdUser = User("Max", 2)
// Compares user to second user
println("user == secondUser: ${user == secondUser}")
// user == secondUser: true
// Compares user to third user
println("user == thirdUser: ${user == thirdUser}")
// user == thirdUser: false
2
3
4
5
6
7
8
9
10
11
12
copy()
通过复制另一个实例来创建新的类实例,可能会有一些不同的属性。
创建实例的副本比直接修改原始实例更为安全,因为那些依赖原始实例的代码不会受到副本的影响,而你对副本所做的操作也不会受到影响。
val user = User("Alex", 1)
// Creates an exact copy of user
println(user.copy())
// User(name=Alex, id=1)
// Creates a copy of user with name: "Max"
println(user.copy("Max"))
// User(name=Max, id=1)
// Creates a copy of user with id: 3
println(user.copy(id = 3))
// User(name=Alex, id=3)
2
3
4
5
6
7
8
9
10
11
12
13
# 空安全
Kotlin 支持可空类型,这意味着所声明的类型可以包含 null 值。默认情况下,类型是不允许接受 null 值的。可空类型是通过在类型声明后添加 ? 来定义的。
fun main() {
// neverNull has String type
var neverNull: String = "This can't be null"
// Throws a compiler error
neverNull = null
// nullable has nullable String type
var nullable: String? = "You can keep a null here"
// This is OK
nullable = null
// By default, null values aren't accepted
var inferredNonNull = "The compiler assumes non-nullable"
// Throws a compiler error
inferredNonNull = null
// notNull doesn't accept null values
fun strLength(notNull: String): Int {
return notNull.length
}
println(strLength(neverNull)) // 18
println(strLength(nullable)) // Throws a compiler error
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 检查是否存在空值
// 判断 maybeString 是否不等于 null ,以及其 length 是否大于零
fun describeString(maybeString: String?): String {
if (maybeString != null && maybeString.length > 0) {
return "String of length ${maybeString.length}"
} else {
return "Empty or null string"
}
}
fun main() {
val nullString: String? = null
println(describeString(nullString))
// Empty or null string
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用安全调用函数
使用安全调用运算符 ?.
fun lengthString(maybeString: String?): Int? = maybeString?.length
fun main() {
val nullString: String? = null
println(lengthString(nullString))
// null
}
2
3
4
5
6
7
可以进行链式操作
person.company?.address?.country
# 使用 Elvis 操作符
如果你使用 Elvis 运算符 ?: 来检测到了 null 的值,你可以提供一个默认值来作为返回值。
fun main() {
val nullString: String? = null
println(nullString?.length ?: 0)
// 0
}
2
3
4
5