ZetCode

Kotlin 扩展函数

最后修改日期:2025 年 3 月 22 日

Kotlin 扩展函数允许你将新的技巧添加到现有的类中,而无需修改它们的蓝图——非常适合改进库或你无法修改的第三方代码。本教程通过生动、真实的例子来阐述扩展函数,使它们的力量栩栩如生。

基本扩展函数

扩展函数通过在其名称前缀目标类型来插入一个类。这里有一个简单的例子,它向 String 添加了一个 welcome 函数,赋予它友好的声音。

BasicExtension.kt
fun String.welcome(): String {
    return "Welcome, $this, to the team!"
}

fun main() {
    val user = "Alice"
    println(user.welcome())
}

welcome 用问候语来丰富 String,使用 this 来引用字符串。想象一下在 HR 应用程序中,用热情欢迎新员工——无需修改类。

带参数的扩展函数

扩展函数可以获取参数来展示它们的实力。这个例子向 String 添加了一个 shout 函数,让你根据需要放大文本。

ExtensionWithParams.kt
fun String.shout(times: Int): String {
    return this.uppercase() + "!".repeat(times)
}

fun main() {
    val alert = "warning"
    println(alert.shout(3))
}

shout 接受一个 times 参数,用感叹号增强字符串。想象一下在通知系统中,将“警告”变成响亮的警报——可定制且快速。

集合的扩展函数

List 这样的集合也可以获得新的能力。这个例子创建了一个 rotate 函数来打乱列表项,保持新鲜感。

CollectionExtension.kt
fun <T> List<T>.rotate(shift: Int): List<T> {
    val size = this.size
    if (size == 0) return this
    val normalizedShift = (shift % size + size) % size
    return this.drop(normalizedShift) + this.take(normalizedShift)
}

fun main() {
    val tasks = listOf("Code", "Test", "Deploy")
    println(tasks.rotate(1))
}

rotate 移动列表元素,用模运算处理边缘情况。想象一下一个任务调度程序循环优先级——将“代码”旋转到后面可以让你的工作流程保持流畅,而无需更改原始 List

可空类型的扩展函数

可空类型也受到喜爱,它们带有优雅处理 null 的扩展。这向 String? 添加了一个 safeTrim 函数,无需因空值而绊倒,即可进行整理。

NullableExtension.kt
fun String?.safeTrim(): String {
    return this?.trim() ?: ""
}

fun main() {
    val input: String? = null
    println(input.safeTrim())
}

safeTrim 修剪一个可空字符串,如果为 null 则默认为空。非常适合表单处理器清理用户输入——无论是否为 null,它都可以通过 Kotlin 的 Elvis 运算符平滑处理。

自定义类的扩展函数

自定义类也可以萌生新的能力。在这里,Person 类获得了一个 needsID 检查,以标记需要额外检查的未成年人。

CustomClassExtension.kt
class Person(val name: String, val age: Int)

fun Person.needsID(): Boolean {
    return this.age < 21
}

fun main() {
    val guest = Person("Bob", 19)
    println(guest.needsID())
}

needsID 用未成年人检查来标记 Person。想象一下在场地门口,标记 21 岁以下的客人进行身份验证——干净地附加到类上,而无需重写它。

伴生对象的扩展函数

伴生对象可以通过扩展进行升级,增强类似静态的行为。这为 User 的伴生对象添加了一个 fromEmail 工厂。

CompanionObjectExtension.kt
class User(val username: String) {
    companion object
}

fun User.Companion.fromEmail(email: String): User {
    return User(email.substringBefore("@"))
}

fun main() {
    val user = User.fromEmail("alice@site.com")
    println(user.username)
}

fromEmail 从电子邮件中创建一个 User,截取用户名。想想注册流程——从电子邮件中提取一个句柄,而不会使 User 类本身变得混乱。

泛型的扩展函数

泛型也屈服于扩展,在各种类型中提供可重用的技巧。这为 List 添加了一个 summarize 函数,用于快速统计。

GenericExtension.kt
fun <T> List<T>.summarize(): String {
    return "Count: ${this.size}, Items: ${this.joinToString()}"
}

fun main() {
    val scores = listOf(85, 92, 78)
    println(scores.summarize())
}

summarize 统计并列出任何 List。想象一个测验应用程序吐出一个分数回顾——通用、简洁,并准备好用于任何数据类型。

带有 Lambda 的扩展

扩展可以使用 lambda 来实现动态行为,让调用者塑造操作。这向 String 添加了一个 transform 函数。

LambdaExtension.kt
fun String.transform(action: (String) -> String): String {
    return action(this)
}

fun main() {
    val text = "hello"
    println(text.transform { it.capitalize() })
}

transform 将字符串交给一个 lambda,这里将其大写。想想文本编辑器——用户选择调整(大写、反转),扩展就执行,所有这些都不需要触及 String

链接扩展

扩展可以链接,堆叠效果以实现流畅的工作流程。这在 String 上配对 maskshorten

ChainingExtension.kt
fun String.mask(): String = this.replaceRange(1, length - 1, "*".repeat(length - 2))
fun String.shorten(max: Int): String = if (length <= max) this else substring(0, max) + "..."

fun main() {
    val email = "alice@site.com"
    println(email.mask().shorten(10))
}

mask 隐藏中间字符,然后 shorten 限制长度。非常适合隐私过滤器——在日志中模糊化电子邮件,然后进行截断以供显示,所有这些都在一个流畅的链中完成。

带有接收者作用域的扩展

扩展可以利用接收者的作用域来获得更丰富的逻辑。这向 Any 添加了 logSelf,使用类型信息进行日志记录。

ReceiverScopeExtension.kt
fun Any.logSelf(): String {
    return "Log: ${this::class.simpleName} = $this"
}

fun main() {
    val num = 42
    println(num.logSelf())
}

logSelf 使用 this 及其类名进行日志条目。非常适合调试——任何对象都可以使用类型上下文报告自己,无需子类化。

使用扩展函数的最佳实践

来源

Kotlin 扩展函数文档

本教程揭开了 Kotlin 扩展函数的面纱,揭示了它们通过新的操作来美化类的诀窍。通过实际的例子,我们已经看到了它们如何增强模块化和重用,从字符串到自定义类型,都具有 Kotlin 的标志性优雅。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有多年的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我写了 1400 多篇文章和 8 本电子书。我拥有超过八年的编程教学经验。

列出 所有 Kotlin 教程