跳到主要内容

Kotlin 作用域函数实战:用 apply/let/run/also 告别临时变量地狱

· 阅读需 6 分钟
重庆 Kotlin User Group

你有没有写过这样的代码?

// 场景:创建一个用户对象并设置各种属性
val user = User()
user.name = "Alice"
user.age = 20
user.email = "alice@example.com"
user.city = "Beijing"

// 或者更糟:为了一个中间结果声明临时变量
val result = computeSomething()
val processed = process(result)
val finalValue = transform(processed)

这种写法能跑,但总让人觉得"不够优雅"。临时变量满天飞,对象初始化代码长得像火车一样。

今天我们来聊聊 Kotlin 的五个作用域函数——apply、let、run、also、with,它们能让你告别临时变量地狱,写出更简洁、更 Kotlin 风格的代码。

Kotlin 2.5 Unicode 代码点 API 实战:用 CodePoint 告别代理对(Surrogate Pair)的噩梦

· 阅读需 6 分钟
重庆 Kotlin User Group

你遇到过这种场景吗?统计一个 emoji 字符串的"字符数",结果数字对不上;或者遍历一个包含罕见汉字的文本,发现一个字被拆成了两个 Char。

来看一段"经典翻车"代码:

val text = "Hello 🌍"
println(text.length) // 7?还是 8?
println(text[6]) // 期望拿到 🌍,实际是一个代理对的高位
println(text[7]) // 这才是代理对的低位

Char 在 Kotlin 中表示一个 UTF-16 编码单元,而像 🌍(U+1F30D)这样的字符超出了 BMP(基本多文种平面),需要两个 Char(即代理对)来表示。直接按 Char 遍历或统计,就会把一个字符拆成两半。

Kotlin 2.5 未使用返回值检查器实战:让编译器帮你揪出那些被静默吞掉的关键结果

· 阅读需 6 分钟
重庆 Kotlin User Group

你有没有遇到过这种场景:代码跑得好好的,测试也通过了,但生产环境就是偶尔出现数据对不上的问题?最后排查了半天,发现罪魁祸首是一个被默默忽略的函数返回值。

来看一段看似无害的代码:

fun processOrder(order: Order) {
val cart = order.cart
// 移除库存不足的商品
cart.items.filter { it.inStock }
// 应用优惠券
cart.total.applyDiscount(order.coupon)
// 保存到数据库
repository.save(cart)
}

问题在哪?filter 不会修改原列表,它返回一个新列表;applyDiscount 如果返回的是新对象而非原地修改,那折扣根本没生效。两行代码的返回值都被静默丢弃了,但编译器一言不发。

Kotlin 2.4.20 when 表达式 invokedynamic 稳定版实战:告别 instanceof 链,拥抱 typeSwitch 字节码

· 阅读需 7 分钟
重庆 Kotlin User Group

你可能不知道,Kotlin 的 when 表达式在 JVM 上编译后,会生成一串冗长的 instanceof 检查。每个分支都是一次类型判断,分支越多,字节码越膨胀。但从 Kotlin 2.4.20 开始,这一切变了——when 表达式正式支持 invokedynamic 编译,默认启用,无需任何额外配置。

来看一个典型的场景:

sealed class Result
data class Success(val data: String) : Result()
data class Error(val message: String, val code: Int) : Result()
object Loading : Result()

fun handleResult(result: Result): String = when (result) {
is Success -> "数据: ${result.data}"
is Error -> "错误 ${result.code}: ${result.message}"
is Loading -> "加载中..."
}

Kotlin 2.4 Map fallback 新 API 实战:用 getOrPutIfNull 和 getOrPutIfMissing 告别手动判空

· 阅读需 6 分钟
重庆 Kotlin User Group

在处理配置、缓存或数据映射时,你一定遇到过这样的场景:从 Map 中获取值,如果不存在就提供默认值。Kotlin 的 getOrDefault() 和 getOrPut() 已经很实用了,但它们都有一个盲区——无法区分"键不存在"和"值为 null"。

来看一个真实的例子:

val config = mutableMapOf<String, String?>(
"username" to "alice",
"theme" to null // 用户明确设置了 theme 为 null
)

// 问题:getOrDefault 无法区分"键不存在"和"值为 null"
val theme1 = config.getOrDefault("theme", "light")
println(theme1) // 输出: light ❌ 错误!用户明确设置了 null,应该保留 null

val theme2 = config.getOrDefault("language", "zh-CN")
println(theme2) // 输出: zh-CN ✅ 正确,键不存在时使用默认值

Kotlin 2.4 集合字面量实战:用方括号语法告别 listOf 和 mutableListOf

· 阅读需 5 分钟
重庆 Kotlin User Group

如果你写过 Kotlin,一定对下面这种代码再熟悉不过了:

val names = listOf("Alice", "Bob", "Charlie")
val scores = mutableListOf(95, 87, 72)
val matrix = listOf(listOf(1, 0), listOf(0, 1))

每次创建集合都要敲一遍 listOf() 或 mutableListOf(),嵌套的时候更是括号套娃。Kotlin 2.4 带来了集合字面量(Collection Literals)——一个期待已久的实验性特性,让你可以直接用方括号 [] 创建集合,就像写 JSON 数组一样自然。

Kotlin 2.4.20 集合新 API 实战:用 allDistinct 和 allEqual 告别手动循环判重

· 阅读需 4 分钟
重庆 Kotlin User Group

在日常开发中,你一定写过这样的逻辑:判断一个列表里的元素是否全部相同,或者检查某个字段是否存在重复。过去我们要么手写 for 循环,要么借助 toSet().size == size 这种"凑合能用"的写法。Kotlin 2.4.20 在标准库中正式引入了 allDistinct()、allEqual() 以及它们的 By 变体,把这些常见需求提升为一等公民 API。

Kotlin 非局部 break/continue 实战:告别标签地狱的循环控制新姿势

· 阅读需 6 分钟
重庆 Kotlin User Group

在 Kotlin 中遍历集合并使用高阶函数时,你一定遇到过这样的困境:想在 lambda 里跳过某次迭代或提前终止循环,却发现 continue 和 break 根本无法直接使用——它们只能作用于字面量循环体,而不是 lambda 内部。于是你不得不搬出标签(label),写出 loop@、return@loop、continue@loop 这样令人眼花缭乱的代码。Kotlin 2.2 将非局部 break 与 continue 正式转为稳定特性,让这类跳转变得自然直观。

Kotlin 2.5 标准库新成员:onTrue、onFalse、ifOrNull 实战指南

· 阅读需 5 分钟
重庆 Kotlin User Group

在日常 Kotlin 开发中,你一定写过这样的代码:调用一个返回 Boolean 的方法,然后根据结果做点副作用——记个日志、发个通知、返回个值。这类模式看似简单,写多了却会让代码变得冗长而重复。Kotlin 2.5.0-Beta1 带来了三个小巧但实用的标准库函数,专门解决这类问题。

Kotlin 标准库 UUID 实战:从 java.util.UUID 到 kotlin.uuid.Uuid 的跨平台迁移指南

· 阅读需 6 分钟
重庆 Kotlin User Group

在几乎所有像样的项目中,你都会遇到 UUID——数据库主键、会话标识、设备指纹、分布式追踪 ID,处处都有它的身影。长期以来,Kotlin 开发者在 JVM 上直接用 java.util.UUID,在 iOS 上用 NSUUID,在 JS 上用 crypto.randomUUID()。三种类型、三套 API、三种序列化方式——跨平台项目中还得写适配层来互相转换。

Kotlin 2.4 终于结束了这个局面:kotlin.uuid.Uuid 正式从实验性 API 毕业,成为标准库的稳定成员。