Kotlin 扩展函数 #
一、扩展函数概述 #
扩展函数允许在不继承类的情况下,为现有类添加新功能。
二、基本语法 #
2.1 定义扩展函数 #
kotlin
fun String.addExclamation(): String {
return this + "!"
}
// 使用
val result = "Hello".addExclamation() // "Hello!"
2.2 this 关键字 #
在扩展函数中,this 指向接收者对象:
kotlin
fun String.printInfo() {
println("Length: ${this.length}")
println("Content: $this")
}
"Kotlin".printInfo()
// Length: 6
// Content: Kotlin
2.3 可空接收者 #
kotlin
fun String?.isNullOrBlank(): Boolean {
return this == null || this.isBlank()
}
val str: String? = null
str.isNullOrBlank() // true
三、扩展函数示例 #
3.1 字符串扩展 #
kotlin
// 判断是否为数字
fun String.isNumeric(): Boolean {
return this.all { it.isDigit() }
}
"12345".isNumeric() // true
"abc".isNumeric() // false
// 截断字符串
fun String.truncate(maxLength: Int): String {
return if (length <= maxLength) this else take(maxLength) + "..."
}
"Hello World".truncate(5) // "Hello..."
// 首字母大写
fun String.capitalizeFirst(): String {
return if (isEmpty()) this else substring(0, 1).uppercase() + substring(1)
}
"kotlin".capitalizeFirst() // "Kotlin"
3.2 集合扩展 #
kotlin
// 获取随机元素
fun <T> List<T>.randomElement(): T {
return this.random()
}
listOf(1, 2, 3, 4, 5).randomElement()
// 分块
fun <T> List<T>.chunked(size: Int): List<List<T>> {
return this.chunked(size)
}
// 求和(数字列表)
fun List<Int>.sum(): Int {
return this.reduce { acc, n -> acc + n }
}
3.3 数值扩展 #
kotlin
// 判断是否为偶数
fun Int.isEven(): Boolean = this % 2 == 0
// 判断是否为素数
fun Int.isPrime(): Boolean {
if (this < 2) return false
for (i in 2..Math.sqrt(this.toDouble()).toInt()) {
if (this % i == 0) return false
}
return true
}
5.isEven() // false
7.isPrime() // true
3.4 日期扩展 #
kotlin
import java.time.LocalDate
import java.time.format.DateTimeFormatter
fun LocalDate.format(pattern: String): String {
return this.format(DateTimeFormatter.ofPattern(pattern))
}
fun String.toDate(pattern: String): LocalDate {
return LocalDate.parse(this, DateTimeFormatter.ofPattern(pattern))
}
val date = LocalDate.now()
date.format("yyyy-MM-dd") // "2024-01-15"
"2024-01-15".toDate("yyyy-MM-dd")
四、扩展属性 #
4.1 定义扩展属性 #
kotlin
val String.halfLength: Int
get() = length / 2
"Kotlin".halfLength // 3
4.2 扩展属性示例 #
kotlin
// 判断字符串是否为空或空白
val String?.isNullOrEmpty: Boolean
get() = this == null || this.isEmpty()
// 判断列表是否只有一个元素
val <T> List<T>.hasSingleElement: Boolean
get() = size == 1
// 获取文件的扩展名
val String.fileExtension: String
get() = substringAfterLast(".", "")
4.3 注意事项 #
扩展属性不能有初始化器,必须定义 getter:
kotlin
// 错误
// val String.doubleLength: Int = length * 2
// 正确
val String.doubleLength: Int
get() = length * 2
五、扩展函数与成员函数 #
5.1 优先级 #
成员函数优先于扩展函数:
kotlin
class Person {
fun greet() = "Hello from member"
}
fun Person.greet() = "Hello from extension"
val person = Person()
person.greet() // "Hello from member"
5.2 重载 #
扩展函数可以重载成员函数:
kotlin
class Calculator {
fun add(a: Int, b: Int) = a + b
}
fun Calculator.add(a: Double, b: Double) = a + b
val calc = Calculator()
calc.add(1, 2) // 3(成员函数)
calc.add(1.0, 2.0) // 3.0(扩展函数)
六、扩展函数的作用域 #
6.1 顶层扩展 #
在文件顶层定义,全局可用:
kotlin
// Utils.kt
package com.example.utils
fun String.isEmail(): Boolean {
return contains("@") && contains(".")
}
6.2 局部扩展 #
在类或函数内部定义:
kotlin
class Processor {
fun process(text: String) {
// 局部扩展函数
fun String.normalize(): String {
return this.trim().lowercase()
}
val normalized = text.normalize()
}
}
6.3 成员扩展 #
在类内部定义扩展:
kotlin
class Service {
// 成员扩展函数
fun String.prependPrefix(): String {
return "PREFIX_$this"
}
fun process(data: String): String {
return data.prependPrefix()
}
}
七、泛型扩展 #
7.1 泛型扩展函数 #
kotlin
fun <T> List<T>.second(): T {
return this[1]
}
fun <T> T?.ifNull(default: T): T {
return this ?: default
}
listOf(1, 2, 3).second() // 2
null.ifNull("default") // "default"
7.2 类型约束 #
kotlin
fun <T : Number> T.doubleValue(): Double {
return this.toDouble()
}
fun <T : Comparable<T>> T.isBetween(a: T, b: T): Boolean {
return this in a..b
}
5.doubleValue() // 5.0
3.isBetween(1, 5) // true
八、扩展函数与接收者 #
8.1 带接收者的 Lambda #
kotlin
fun buildString(builder: StringBuilder.() -> Unit): String {
val sb = StringBuilder()
sb.builder()
return sb.toString()
}
val result = buildString {
append("Hello")
append(", ")
append("Kotlin")
}
// "Hello, Kotlin"
8.2 DSL 构建 #
kotlin
class HtmlBuilder {
private val content = StringBuilder()
fun body(block: HtmlBuilder.() -> Unit) {
content.append("<body>")
block()
content.append("</body>")
}
fun p(text: String) {
content.append("<p>$text</p>")
}
override fun toString() = content.toString()
}
fun html(block: HtmlBuilder.() -> Unit): String {
return HtmlBuilder().apply(block).toString()
}
val result = html {
body {
p("Hello, Kotlin!")
}
}
// <body><p>Hello, Kotlin!</p></body>
九、标准库扩展函数 #
9.1 标准扩展 #
kotlin
// let
"Kotlin".let { println(it) }
// run
"Kotlin".run { println(length) }
// apply
StringBuilder().apply { append("Hello") }
// also
listOf(1, 2, 3).also { println(it) }
// takeIf
"Kotlin".takeIf { it.length > 3 }
// repeat
3.times { println("Hello") }
9.2 集合扩展 #
kotlin
val list = listOf(1, 2, 3, 4, 5)
list.map { it * 2 }
list.filter { it > 2 }
list.find { it == 3 }
list.any { it > 3 }
list.all { it > 0 }
十、实战示例 #
10.1 验证扩展 #
kotlin
fun String.isValidEmail(): Boolean {
return matches(Regex("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"))
}
fun String.isValidPhone(): Boolean {
return matches(Regex("^\\d{11}$"))
}
fun String.isValidUrl(): Boolean {
return startsWith("http://") || startsWith("https://")
}
"test@example.com".isValidEmail() // true
"13800138000".isValidPhone() // true
10.2 转换扩展 #
kotlin
fun String.toCamelCase(): String {
return split("_", "-")
.mapIndexed { index, word ->
if (index == 0) word.lowercase()
else word.replaceFirstChar { it.uppercase() }
}
.joinToString("")
}
fun String.toSnakeCase(): String {
return replace(Regex("([a-z])([A-Z])")) { "${it.groupValues[1]}_${it.groupValues[2]}" }
.lowercase()
}
"hello_world".toCamelCase() // "helloWorld"
"helloWorld".toSnakeCase() // "hello_world"
10.3 时间扩展 #
kotlin
import java.time.Duration
import java.time.Instant
fun Instant.formatDuration(): String {
val duration = Duration.between(this, Instant.now())
val seconds = duration.seconds
return when {
seconds < 60 -> "$seconds 秒前"
seconds < 3600 -> "${seconds / 60} 分钟前"
seconds < 86400 -> "${seconds / 3600} 小时前"
else -> "${seconds / 86400} 天前"
}
}
Instant.now().minusSeconds(300).formatDuration() // "5 分钟前"
十一、最佳实践 #
11.1 命名规范 #
kotlin
// 推荐:动词开头
fun String.removeSpaces(): String
fun List<Int>.sumAll(): Int
// 布尔返回值用 is/has/can
fun String.isNumeric(): Boolean
fun List<Int>.hasDuplicates(): Boolean
11.2 避免滥用 #
kotlin
// 不推荐:过度使用扩展
fun String.doEverything(): String { }
// 推荐:职责单一
fun String.trimAll(): String
fun String.removeSpecialChars(): String
11.3 使用扩展文件组织 #
kotlin
// StringExtensions.kt
package com.example.extensions
fun String.isEmail(): Boolean { }
fun String.isPhone(): Boolean { }
fun String.truncate(max: Int): String { }
// CollectionExtensions.kt
package com.example.extensions
fun <T> List<T>.second(): T { }
fun <T> List<T>.randomElement(): T { }
十二、总结 #
扩展函数要点:
| 特性 | 说明 |
|---|---|
| 语法 | fun Type.functionName() |
| this | 指向接收者对象 |
| 扩展属性 | val Type.propertyName |
| 优先级 | 成员函数优先 |
| 作用域 | 顶层、局部、成员 |
下一步,让我们学习 内联函数!
最后更新:2026-03-27