Kotlin快速入门

这是一篇 Kotlin 快速入门笔记,适合有 JS / TS 基础的开发者阅读。文章通过大量代码示例,梳理 Kotlin 的变量、类型、集合、控制流、函数、Lambda、类和数据类等基础语法,帮助读者快速建立 Kotlin 的语法体系。

1. Kotlin 基础

1.1入口文件

fun main() {
    println("Hello, world!")
    // Hello, world!
}

1.2变量

写法 含义 类似 JS / TS
val 只读变量 const
var 可变变量 let
String? 可空变量 `string
lateinit var 延迟初始化变量 先声明后赋值
const val 编译期常量 真正常量
val xxx by lazy 懒加载变量 第一次用时初始化
fun main() {
    // 1. val:只读变量,类似 JS / TS 的 const
    val name = "Tom"
    println(name)

    // name = "Jack" // 报错:val 不能重新赋值


    // 2. var:可变变量,类似 JS / TS 的 let
    var age = 18
    age = 20
    println(age)


    // 3. String?:可空变量,类似 TS 的 string | null
    var title: String? = "Kotlin 学习笔记"
    title = null
    println(title)


    // 4. lateinit var:延迟初始化变量,先声明,后赋值
    val user = User()
    user.username = "Alice"
    println(user.username)


    // 5. const val:编译期常量
    println(API_URL)


    // 6. val xxx by lazy:懒加载变量,第一次使用时才初始化
    println(config)
    println(config)
}

// lateinit var 通常写在类里面
class User {
    lateinit var username: String
}

// const val 必须写在顶层、object 或 companion object 中
const val API_URL = "https://example.com"

// lazy 变量第一次被访问时,才会执行初始化代码
val config: String by lazy {
    println("初始化 config")
    "这是配置内容"
}

1.3 字符串模板

fun main() {
    val name = "Tom"
    val age = 18
    val price = 99

    // 变量插值
    println("name = $name")

    // 表达式插值
    println("next age = ${age + 1}")

    // 属性访问
    println("name length = ${name.length}")

    // 函数调用
    println("upper name = ${name.uppercase()}")

    // if 表达式
    println("type = ${if (age >= 18) "adult" else "child"}")

    // 输出 $ 符号
    println("price = \$$price")

    // 多行字符串
    val message = """
        name = $name
        age = $age
        price = ${'$'}$price
    """.trimIndent()

    println(message)
}

1.4基本数据类型

类型 含义 示例 说明
Byte 8 位整数 val a: Byte = 127 范围:-128 ~ 127
Short 16 位整数 val a: Short = 1000 范围比 Byte
Int 32 位整数 val a: Int = 100 默认整数类型
Long 64 位整数 val a: Long = 100L 数字后加 L
Float 32 位浮点数 val a: Float = 3.14F 数字后加 Ff
Double 64 位浮点数 val a: Double = 3.14 默认小数类型
Boolean 布尔值 val ok: Boolean = true 只有 true / false
Char 单个字符 val c: Char = 'A' 使用单引号
String 字符串 val s: String = "Hello" 使用双引号
Array<T> 数组 val arr = arrayOf(1, 2, 3) 固定长度,元素类型统一
UByte 无符号 8 位整数 val a: UByte = 255u 范围:0 ~ 255
UShort 无符号 16 位整数 val a: UShort = 65535u 无负数
UInt 无符号 32 位整数 val a: UInt = 100u 数字后加 u
ULong 无符号 64 位整数 val a: ULong = 100uL 数字后加 uL
fun main() {
    val age: Int = 18
    val money: Long = 100000L
    val price: Double = 19.99
    val height: Float = 175.5F
    val isLogin: Boolean = true
    val grade: Char = 'A'
    val name: String = "Tom"
    val numbers: Array<Int> = arrayOf(1, 2, 3)

    println(age)
    println(money)
    println(price)
    println(height)
    println(isLogin)
    println(grade)
    println(name)
    println(numbers.contentToString())
}

1.5集合

类型 含义 是否有序 是否允许重复 是否可修改 示例
List<T> 只读列表 listOf(1, 2, 3)
MutableList<T> 可变列表 mutableListOf(1, 2, 3)
Set<T> 只读集合 通常不关心顺序 setOf(1, 2, 3)
MutableSet<T> 可变集合 通常不关心顺序 mutableSetOf(1, 2, 3)
Map<K, V> 只读键值对 按实现决定 Key 不允许重复 mapOf("a" to 1)
MutableMap<K, V> 可变键值对 按实现决定 Key 不允许重复 mutableMapOf("a" to 1)

常用操作函数:

函数 作用 示例
size 获取数量 list.size
isEmpty() 是否为空 list.isEmpty()
contains() 是否包含元素 list.contains("A")
first() 第一个元素 list.first()
last() 最后一个元素 list.last()
get(index) 根据索引获取 list.get(0)
[index] 根据索引获取 list[0]
filter {} 过滤 list.filter { it > 10 }
map {} 映射转换 list.map { it * 2 }
forEach {} 遍历 list.forEach { println(it) }

1.6控制流

1.6.1 if && when

语法 作用 是否能返回值 适合场景 示例形式
if 条件判断 简单二选一判断 if (age >= 18) "adult" else "child"
if else if 多条件判断 条件数量较少 if (...) ... else if (...) ... else ...
when (value) 按值匹配 类似 switch,适合多个固定值 when (day) { 1 -> ... }
when 多值匹配 多个值走同一分支 多个 case 结果相同 1, 2, 3 -> ...
when 范围匹配 判断值是否在范围内 分数、年龄、区间判断 in 60..100 -> ...
when 类型匹配 判断变量类型 Any 类型、父类类型判断 is String -> ...
when {} 不带参数的条件判断 替代复杂 if else if when { score >= 90 -> ... }
fun main() {
    val age = 18
    val score = 85
    val day = 6
    val value: Any = "Kotlin"

    // 1. if:简单二选一,替代三元表达式
    val userType = if (age >= 18) "adult" else "child"

    // 2. if else if:多个条件判断
    val ageLevel = if (age < 18) {
        "未成年"
    } else if (age < 60) {
        "成年人"
    } else {
        "老年人"
    }

    // 3. when(value):按固定值匹配
    val dayName = when (day) {
        1 -> "Monday"
        2 -> "Tuesday"
        3 -> "Wednesday"
        4 -> "Thursday"
        5 -> "Friday"
        6, 7 -> "Weekend" // 多个值匹配同一个分支
        else -> "Unknown"
    }

    // 4. when:范围匹配
    val scoreLevel = when (score) {
        in 90..100 -> "A"
        in 80..89 -> "B"
        in 60..79 -> "C"
        in 0..59 -> "D"
        else -> "Invalid"
    }

    // 5. when:类型匹配
    val typeResult = when (value) {
        is String -> "String length = ${value.length}"
        is Int -> "Int value = $value"
        is Boolean -> "Boolean value = $value"
        else -> "Unknown type"
    }

    // 6. when {}:不带参数,类似 if else if
    val comment = when {
        score >= 90 -> "优秀"
        score >= 80 -> "良好"
        score >= 60 -> "及格"
        else -> "不及格"
    }

    println(userType)
    println(ageLevel)
    println(dayName)
    println(scoreLevel)
    println(typeResult)
    println(comment)
}

1.6.2Ranges

写法 含义 是否包含结束值 示例 结果 / 含义
1..5 创建闭区间 包含 1..5 1, 2, 3, 4, 5
1..<5 创建半开区间 不包含 1..<5 1, 2, 3, 4
1 until 5 创建半开区间 不包含 1 until 5 1, 2, 3, 4
5 downTo 1 倒序区间 包含 5 downTo 1 5, 4, 3, 2, 1
1..10 step 2 指定步长 包含 1..10 step 2 1, 3, 5, 7, 9
5 downTo 1 step 2 倒序指定步长 包含 5 downTo 1 step 2 5, 3, 1
in 判断是否在范围内 - 3 in 1..5 true
!in 判断是否不在范围内 - 6 !in 1..5 true
'a'..'z' 字符范围 包含 'c' in 'a'..'z' true
array.indices 数组 / 集合索引范围 包含 list.indices 0..最后一个索引
fun main() {
    // 1. 闭区间:包含结束值
    for (i in 1..5) {
        print("$i ")
    }
    println()
    // 输出:1 2 3 4 5


    // 2. 半开区间:不包含结束值
    for (i in 1..<5) {
        print("$i ")
    }
    println()
    // 输出:1 2 3 4


    // 3. until:也是半开区间,不包含结束值
    for (i in 1 until 5) {
        print("$i ")
    }
    println()
    // 输出:1 2 3 4


    // 4. downTo:倒序
    for (i in 5 downTo 1) {
        print("$i ")
    }
    println()
    // 输出:5 4 3 2 1


    // 5. step:指定步长
    for (i in 1..10 step 2) {
        print("$i ")
    }
    println()
    // 输出:1 3 5 7 9


    // 6. downTo + step:倒序指定步长
    for (i in 10 downTo 1 step 3) {
        print("$i ")
    }
    println()
    // 输出:10 7 4 1


    // 7. in:判断是否在范围内
    val age = 18

    if (age in 18..60) {
        println("成年人")
    }


    // 8. !in:判断是否不在范围内
    val score = 120

    if (score !in 0..100) {
        println("分数非法")
    }


    // 9. Char 范围
    val char = 'k'

    if (char in 'a'..'z') {
        println("小写字母")
    }


    // 10. indices:遍历集合索引
    val names = listOf("Tom", "Alice", "Jack")

    for (index in names.indices) {
        println("index = $index, value = ${names[index]}")
    }
}

1.6.3Loops

语法 含义 是否先判断条件 适合场景 示例
for (item in collection) 遍历集合元素 遍历 List、Set、Array for (name in names)
for (i in range) 遍历范围 固定次数循环 for (i in 1..5)
for (i in collection.indices) 遍历索引 需要索引访问元素 for (i in list.indices)
for ((index, value) in list.withIndex()) 同时拿索引和值 需要索引和值 for ((i, v) in list.withIndex())
while (condition) 条件循环 不确定循环次数 while (count < 5)
do { } while (condition) 先执行一次再判断 至少执行一次 do { ... } while (...)
break 退出循环 - 满足条件时停止循环 break
continue 跳过本次循环 - 跳过当前项,继续下一次 continue
fun main() {
    // 1. for:遍历集合元素
    val names = listOf("Tom", "Alice", "Jack")

    for (name in names) {
        println(name)
    }


    // 2. for:遍历范围
    for (i in 1..5) {
        println("i = $i")
    }


    // 3. for:半开区间,不包含结束值
    for (i in 0 until 5) {
        println("index = $i")
    }


    // 4. for:倒序遍历
    for (i in 5 downTo 1) {
        println("倒序 i = $i")
    }


    // 5. for:指定步长
    for (i in 1..10 step 2) {
        println("step i = $i")
    }


    // 6. for:遍历集合索引
    for (index in names.indices) {
        println("index = $index, value = ${names[index]}")
    }


    // 7. for:同时获取索引和值
    for ((index, value) in names.withIndex()) {
        println("index = $index, value = $value")
    }


    // 8. while:先判断条件,再执行
    var count = 0

    while (count < 3) {
        println("while count = $count")
        count++
    }


    // 9. do while:先执行一次,再判断条件
    var num = 0

    do {
        println("do while num = $num")
        num++
    } while (num < 3)


    // 10. break:退出循环
    for (i in 1..10) {
        if (i == 5) {
            break
        }

        println("break 示例 i = $i")
    }


    // 11. continue:跳过本次循环
    for (i in 1..5) {
        if (i == 3) {
            continue
        }

        println("continue 示例 i = $i")
    }
}

1.7函数

类型 写法 含义 适合场景
普通函数 fun name() {} 定义一个函数 复用一段逻辑
带参数函数 fun add(a: Int, b: Int) 函数接收参数 需要外部传值
带返回值函数 fun add(...): Int 指定返回类型 计算并返回结果
Unit 返回值 fun log(): Unit 没有实际返回值 类似 JS 的 void
单表达式函数 fun add(a: Int, b: Int) = a + b 简化函数写法 函数体只有一行表达式
默认参数 fun hello(name: String = "Tom") 参数有默认值 调用时可省略参数
命名参数 hello(name = "Alice") 调用时指定参数名 提高可读性
可变参数 vararg nums: Int 接收多个同类型参数 参数数量不固定
Lambda { x: Int -> x * 2 } 匿名函数表达式 临时传递逻辑
函数类型 (Int) -> Int 表示函数的类型 函数作为变量 / 参数
高阶函数 fun calc(action: () -> Unit) 参数或返回值是函数 回调、集合操作
trailing lambda repeat(3) { ... } 最后一个参数是 Lambda 时可放到括号外 Kotlin 常见写法
it 简写 { it * 2 } 单参数 Lambda 的默认参数名 简化单参数 Lambda
fun main() {
    // 1. 普通函数
    sayHello()

    // 2. 带参数函数
    greet("Tom")

    // 3. 带返回值函数
    val sum = add(10, 20)
    println(sum)

    // 4. 单表达式函数
    println(multiply(3, 4))

    // 5. 默认参数
    hello()
    hello("Alice")

    // 6. 命名参数
    createUser(name = "Jack", age = 18)

    // 7. 可变参数 vararg
    println(sumAll(1, 2, 3, 4, 5))

    // 8. Lambda:赋值给变量
    val double: (Int) -> Int = { x: Int -> x * 2 }
    println(double(10))

    // 9. Lambda:单参数时可以用 it
    val triple: (Int) -> Int = { it * 3 }
    println(triple(10))

    // 10. 高阶函数:函数作为参数
    runTask {
        println("执行任务")
    }

    // 11. 自定义高阶函数
    val result = calculate(10, 20) { a, b ->
        a + b
    }
    println(result)

    // 12. 集合中常见 Lambda
    val numbers = listOf(1, 2, 3, 4, 5)

    val evenNumbers = numbers.filter { it % 2 == 0 }
    val doubleNumbers = numbers.map { it * 2 }

    println(evenNumbers)
    println(doubleNumbers)
}

// 普通函数
fun sayHello() {
    println("Hello Kotlin")
}

// 带参数函数
fun greet(name: String) {
    println("Hello, $name")
}

// 带返回值函数
fun add(a: Int, b: Int): Int {
    return a + b
}

// 单表达式函数
fun multiply(a: Int, b: Int): Int = a * b

// 返回 Unit,Unit 可以省略
fun log(message: String): Unit {
    println(message)
}

// 默认参数
fun hello(name: String = "Tom") {
    println("Hello, $name")
}

// 命名参数示例
fun createUser(name: String, age: Int) {
    println("name = $name, age = $age")
}

// 可变参数
fun sumAll(vararg numbers: Int): Int {
    var result = 0

    for (number in numbers) {
        result += number
    }

    return result
}

// 高阶函数:参数是一个函数
fun runTask(task: () -> Unit) {
    println("任务开始")
    task()
    println("任务结束")
}

// 高阶函数:接收两个 Int 和一个 Lambda
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

1.7.1扩展函数

内容 写法 含义 适合场景
扩展函数 fun String.xxx() 给已有类型“增加函数” 不改源码的情况下扩展能力
接收者类型 String / Int / User 被扩展的类型 决定这个函数能被谁调用
接收者对象 this 当前调用扩展函数的对象 在函数内部访问调用者
可空类型扩展 fun String?.xxx() 给可空类型扩展函数 统一处理 null
泛型扩展函数 fun <T> List<T>.xxx() 给泛型类型扩展函数 扩展集合类能力
扩展属性 val String.xxx: Int 给已有类型增加“属性” 只读计算属性
作用范围 当前文件 / import 后可用 不是全局自动生效 需要在使用处能访问到
本质 静态函数 不是修改原类 编译后类似工具函数
fun main() {
    // 1. 给 String 扩展函数
    val text = "hello"

    println(text.addPrefix())
    println(text.firstChar())


    // 2. this 表示当前调用者
    val name = "Tom"

    println(name.sayHello())


    // 3. 给可空类型扩展函数
    val title1: String? = "Kotlin"
    val title2: String? = null

    println(title1.orDefault())
    println(title2.orDefault())


    // 4. 给自定义类型扩展函数
    val user = User("Alice", 20)

    println(user.displayInfo())


    // 5. 给集合扩展函数
    val numbers = listOf(1, 2, 3, 4, 5)

    println(numbers.secondOrNull())
    println(numbers.joinWithDash())


    // 6. 扩展属性
    println(text.lastIndex)
}


// 1. String 扩展函数
fun String.addPrefix(): String {
    return "Text: $this"
}


// 单表达式写法
fun String.firstChar(): Char {
    return this[0]
}


// 2. this 表示当前调用扩展函数的对象
fun String.sayHello(): String {
    return "Hello, $this"
}


// 3. 可空类型扩展函数
fun String?.orDefault(): String {
    return this ?: "默认值"
}


// 4. 自定义类型
data class User(
    val name: String,
    val age: Int
)

fun User.displayInfo(): String {
    return "name = $name, age = $age"
}


// 5. 泛型集合扩展函数
fun <T> List<T>.secondOrNull(): T? {
    return if (this.size >= 2) this[1] else null
}


fun List<Int>.joinWithDash(): String {
    return this.joinToString("-")
}


// 6. 扩展属性
val String.lastIndex: Int
    get() = this.length - 1

1.7.2带接收器的lambda表达式

写法 含义 类似理解
(T) -> R 普通 lambda,T 是参数 JS 里的 (obj) => result
T.() -> R 带接收者的 lambda,Tthis T 的上下文里执行代码
Canvas.() -> Unit lambda 内部的 thisCanvas 可以直接调用 Canvas 的方法
MutableList<Int>.() -> Unit lambda 内部的 thisMutableList<Int> 可以直接 add(...)
StringBuilder.() -> Unit lambda 内部的 thisStringBuilder 可以直接 append(...)
T.(A) -> R 既有接收者 T,又有普通参数 A thisT,同时还能接收参数
this.xxx 显式访问接收者对象 this.drawCircle()
xxx 省略 this 后的写法 drawCircle()
class Canvas {
    fun drawCircle() {
        println("Drawing circle")
    }

    fun drawSquare() {
        println("Drawing square")
    }
}

// block 的类型是 Canvas.() -> Unit
// 表示这个 lambda 执行时,内部的 this 是 Canvas
fun render(block: Canvas.() -> Unit) {
    val canvas = Canvas()

    // 等价于 block(canvas)
    // 但因为 block 是带接收者的 lambda,所以写成 canvas.block()
    canvas.block()
}

fun main() {
    render {
        // 这里的 this 是 Canvas

        drawCircle()
        drawSquare()

        // 等价于:
        // this.drawCircle()
        // this.drawSquare()
    }
}

1.8类

类型 写法 含义 适合场景
普通类 class User 定义一个类 需要封装属性和行为
主构造函数 class User(val name: String) 类名后面的构造函数 创建对象时传入参数
成员属性 val name: String / var age: Int 对象上的属性 保存对象状态
成员方法 fun sayHello() 类里面的函数 定义对象行为
init init {} 初始化代码块 构造对象时执行额外逻辑
普通构造参数 class User(name: String) 只是参数,不是属性 只在初始化阶段使用
只读属性参数 class User(val name: String) 构造参数 + 只读属性 创建后可访问,不可修改
可变属性参数 class User(var name: String) 构造参数 + 可变属性 创建后可访问,可修改
数据类 data class User(...) 专门表示数据的类 DTO、接口返回值、状态对象
copy() user.copy(age = 20) 复制对象并修改部分字段 创建新对象
解构声明 val (name, age) = user 拆出数据类属性 快速取值
自动生成方法 toString() / equals() / hashCode() 数据类自动生成 比较、打印、集合操作
fun main() {
    // 1. 普通类:需要自己定义属性和方法
    val user = User("Tom", 18)

    println(user.name)
    println(user.age)

    user.age = 20
    println(user.age)

    user.sayHello()


    // 2. 构造参数不加 val / var:只是参数,不是对象属性
    val product = Product("Phone", 3999.0)

    println(product.displayName)
    println(product.isExpensive)

    // println(product.name)  // 报错:name 不是属性
    // println(product.price) // 报错:price 不是属性


    // 3. 数据类:主要用来存数据
    val person1 = Person("Alice", 20)
    val person2 = Person("Alice", 20)

    // data class 自动生成 toString()
    println(person1)

    // data class 自动生成 equals()
    println(person1 == person2) // true


    // 4. copy:复制对象,并修改部分字段
    val person3 = person1.copy(age = 21)

    println(person3)


    // 5. 解构声明
    val (name, age) = person1

    println(name)
    println(age)
}

// 普通类
class User(
    val name: String, // 只读属性
    var age: Int     // 可变属性
) {
    init {
        println("User 被创建了:$name, $age")
    }

    fun sayHello() {
        println("Hello, my name is $name")
    }
}

// 构造参数没有 val / var,只能在初始化阶段使用
class Product(name: String, price: Double) {
    val displayName = "商品名称:$name"
    val isExpensive = price > 1000

    init {
        println("创建商品:$name, 价格:$price")
    }
}

// 数据类
data class Person(
    val name: String,
    val age: Int
)

1.8.1类继承 && 抽象类 && 接口

概念 写法 含义 关键点
普通类 class User 定义一个类 默认不能被继承
可继承类 open class Animal 允许其他类继承 Kotlin 类默认是 final
继承类 class Dog : Animal() Dog 继承 Animal 父类有构造函数时要调用
抽象类 abstract class Product 不能直接创建对象,只能被继承 可以有普通方法,也可以有抽象方法
抽象属性 abstract val category: String 子类必须实现的属性 子类用 override 实现
抽象方法 abstract fun work() 子类必须实现的方法 没有方法体
接口 interface Flyable 定义一种能力或规范 不能有构造函数
实现接口 class Bird : Flyable 类实现接口能力 接口后面没有 ()
多接口实现 class Bird : Flyable, Runnable 一个类可以实现多个接口 Kotlin 类只能单继承,但接口可以多个
重写成员 override fun play() 实现或覆盖父级成员 Kotlin 必须显式写 override
接口委托 class A(b: B) : I by b 把接口实现交给另一个对象 可以减少手动转发代码
顶层父类 Any Kotlin 所有类最终都继承自它 类似 Java Object
// 抽象类:表示“是什么”
abstract class Animal(
    val name: String
) {
    // 抽象属性:子类必须实现
    abstract val type: String

    // 抽象方法:子类必须实现
    abstract fun makeSound()

    // 普通方法:子类可以直接复用
    fun info() {
        println("$name is a $type")
    }
}

// 接口:表示“能做什么”
interface Runnable {
    fun run()
}

interface Flyable {
    fun fly()
}

// Dog 继承 Animal,并实现 Runnable 接口
class Dog(name: String) : Animal(name), Runnable {
    override val type: String = "Dog"

    override fun makeSound() {
        println("$name says: Woof!")
    }

    override fun run() {
        println("$name is running")
    }
}

// Bird 继承 Animal,并实现 Runnable 和 Flyable 两个接口
class Bird(name: String) : Animal(name), Runnable, Flyable {
    override val type: String = "Bird"

    override fun makeSound() {
        println("$name says: Tweet!")
    }

    override fun run() {
        println("$name is running")
    }

    override fun fly() {
        println("$name is flying")
    }
}

fun main() {
    val dog = Dog("Buddy")
    dog.info()
    dog.makeSound()
    dog.run()

    val bird = Bird("Sky")
    bird.info()
    bird.makeSound()
    bird.run()
    bird.fly()
}

1.8.2 Objects

类型 写法 含义 常见用途 类似 JS / TS
对象声明 object AppConfig { ... } 定义一个单例对象 全局配置、工具对象、共享状态 单例对象 / module object
伴生对象 companion object { ... } 绑定在类上的单例对象 工厂方法、常量、模拟静态方法 static 方法/属性
对象表达式 object : Interface { ... } 创建匿名对象 临时实现接口、回调对象 匿名对象 / inline object
数据对象 data object Loading 带更好 toString() / 相等语义的单例 sealed 状态、固定状态值 enum-like singleton
对象继承接口 object X : SomeInterface 单例对象实现接口 默认实现、全局处理器 singleton implements interface
// 1. 单例对象:全局配置
object AppConfig {
    const val APP_NAME = "KotlinDemo"

    fun printConfig() {
        println("App name: $APP_NAME")
    }
}

// 2. 类 + companion object:工厂方法
class User private constructor(
    val name: String
) {
    companion object {
        fun create(name: String): User {
            return User(name)
        }
    }
}

// 3. 接口
interface Logger {
    fun log(message: String)
}

// 4. object expression:临时实现接口
fun runTask(logger: Logger) {
    logger.log("Task started")
}

// 5. data object:固定状态
sealed interface TaskState

data object Idle : TaskState
data object Loading : TaskState
data class Finished(val result: String) : TaskState

fun main() {
    AppConfig.printConfig()

    val user = User.create("Tom")
    println(user.name)

    runTask(object : Logger {
        override fun log(message: String) {
            println("[LOG] $message")
        }
    })

    val state: TaskState = Finished("OK")

    when (state) {
        Idle -> println("Idle")
        Loading -> println("Loading")
        is Finished -> println("Finished: ${state.result}")
    }
}

1.9作用域函数

函数 对象引用 返回值 主要用途 常见场景
let it Lambda 最后一行结果 转换结果、处理可空对象 xxx?.let { ... }
run this Lambda 最后一行结果 在对象作用域内计算结果 初始化后返回计算值
with this Lambda 最后一行结果 对已有对象连续操作 不需要链式调用时
apply this 原对象本身 配置对象属性 创建对象后初始化属性
also it 原对象本身 附加操作、副作用 打日志、调试、额外处理
fun main() {
    val user = User("Tom", 18)

    // 1. let:常用于可空对象处理,返回 Lambda 最后一行结果
    val nameLength = user.name.let {
        println("name = $it")
        it.length
    }

    println(nameLength)


    // 2. run:this 指向当前对象,返回 Lambda 最后一行结果
    val description = user.run {
        "name = $name, age = $age"
    }

    println(description)


    // 3. with:不是扩展函数,适合对已有对象做多次操作
    val info = with(user) {
        println("访问 name = $name")
        println("访问 age = $age")

        "User($name, $age)"
    }

    println(info)


    // 4. apply:返回原对象,常用于对象初始化
    val newUser = User("Alice", 20).apply {
        age = 21
        city = "Shanghai"
    }

    println(newUser)


    // 5. also:返回原对象,常用于日志、调试、额外操作
    val resultUser = User("Jack", 30).also {
        println("创建了用户:$it")
    }

    println(resultUser)


    // 6. 可空对象常见写法
    val nullableName: String? = "Kotlin"

    nullableName?.let {
        println("字符串不为空,长度 = ${it.length}")
    }


    // 7. 链式调用示例
    val finalUser = User("Bob", 25)
        .also {
            println("初始化前:$it")
        }
        .apply {
            age = 26
            city = "Beijing"
        }
        .also {
            println("初始化后:$it")
        }

    println(finalUser)
}

data class User(
    var name: String,
    var age: Int,
    var city: String = ""
)