Kotlin扩展函数与属性

扩展函数和属性是Kotlin中最具特色的功能之一,它们允许我们在不修改原有类的情况下为类添加新功能。这种设计既保持了类的封装性,又提供了强大的扩展能力。

一、扩展函数:为现有类添加新行为

1.1 基础扩展函数

扩展函数允许我们为任何类(包括Java类)添加新方法:

复制代码
// 为String类添加扩展函数
fun String.addExclamation(): String {
    return "$this!"
}

// 为Int添加平方计算
fun Int.square(): Int {
    return this * this
}

fun main() {
    val greeting = "Hello"
    println(greeting.addExclamation()) // 输出: Hello!
    
    val number = 5
    println(number.square()) // 输出: 25
}

1.2 实用扩展函数示例

1.2.1 集合操作扩展

复制代码
// 安全获取元素,越界时返回null
fun <T> List<T>.getSafe(index: Int): T? {
    return if (index in indices) get(index) else null
}

// 统计满足条件的元素数量
fun <T> Iterable<T>.countBy(predicate: (T) -> Boolean): Int {
    return count(predicate)
}

fun main() {
    val list = listOf("Apple", "Banana", "Cherry")
    
    println(list.getSafe(1)) // 输出: Banana
    println(list.getSafe(5)) // 输出: null
    
    val count = list.countBy { it.length > 5 }
    println("长度>5的单词数: $count") // 输出: 2
}

1.2.2 日期时间处理扩展

复制代码
// 计算两个日期之间的天数
fun LocalDate.daysUntil(other: LocalDate): Long {
    return ChronoUnit.DAYS.between(this, other)
}
 
// 判断是否是周末
fun LocalDate.isWeekend(): Boolean {
    return dayOfWeek.value in listOf(6, 7) // 6=周六, 7=周日
}
 
fun main() {
    val today = LocalDate.now()
    val futureDate = today.plusDays(10)
    
    println("距离未来日期还有 ${today.daysUntil(futureDate)} 天")
    println("今天是周末吗? ${today.isWeekend()}")
}

1.3 扩展函数的高级用法

1.3.1 可空接收者扩展

复制代码
// 为可空String添加扩展函数
fun String?.orEmpty(): String {
    return this ?: ""
}

// 安全解析Int
fun String?.toIntOrZero(): Int {
    return this?.toIntOrNull() ?: 0
}

fun main() {
    val nullString: String? = null
    println(nullString.orEmpty().length) // 输出: 0
    
    val numString: String? = "42"
    println(numString.toIntOrZero()) // 输出: 42
    println(nullString.toIntOrZero()) // 输出: 0
}

1.3.2 泛型扩展函数

复制代码
// 交换Map中的键值对
fun <K, V> Map<K, V>.invert(): Map<V, K> {
    return map { Pair(it.value, it.key) }.toMap()
}

// 安全转换集合类型
fun <T, R> Collection<T>.convertAll(transform: (T) -> R): List<R> {
    return mapNotNull { runCatching { transform(it) }.getOrNull() }
}

fun main() {
    val originalMap = mapOf("A" to 1, "B" to 2)
    println(originalMap.invert()) // 输出: {1=A, 2=B}
    
    val strings = listOf("1", "2", "three", "4")
    val numbers = strings.convertAll { it.toInt() }
    println(numbers) // 输出: [1, 2, 4]
}

二、扩展属性:为类添加新属性

扩展属性允许我们为现有类添加计算属性:
2.1 基础扩展属性

复制代码
// 为String添加扩展属性:单词数
val String.wordCount: Int
    get() = split("\\s+".toRegex()).filter { it.isNotBlank() }.size

// 为Int添加扩展属性:是否为偶数
val Int.isEven: Boolean
    get() = this % 2 == 0

fun main() {
    val text = "Kotlin extensions are powerful"
    println("单词数: ${text.wordCount}") // 输出: 4
    
    println("10是偶数吗? ${10.isEven}") // 输出: true
    println("7是偶数吗? ${7.isEven}")   // 输出: false
}

三、实战案例:构建DSL风格的验证库

复制代码
// 验证结果类
data class ValidationResult(
    val isValid: Boolean,
    val errors: List<String> = emptyList()
) {
    operator fun plus(other: ValidationResult): ValidationResult {
        return ValidationResult(
            isValid = isValid && other.isValid,
            errors = errors + other.errors
        )
    }
}

// 验证器扩展函数
fun String.validate(block: StringValidator.() -> Unit): ValidationResult {
    val validator = StringValidator(this)
    validator.block()
    return validator.result
}

// 验证器类
class StringValidator(private val value: String) {
    private var result = ValidationResult(true)
    
    fun notEmpty(message: String = "不能为空") {
        if (value.isBlank()) {
            result = ValidationResult(false, result.errors + message)
        }
    }
    
    fun minLength(length: Int, message: String = "长度不足") {
        if (value.length < length) {
            result = ValidationResult(false, result.errors + "$message (最小$length)")
        }
    }
    
    fun maxLength(length: Int, message: String = "长度超限") {
        if (value.length > length) {
            result = ValidationResult(false, result.errors + "$message (最大$length)")
        }
    }
    
    fun matches(regex: Regex, message: String = "格式不匹配") {
        if (!value.matches(regex)) {
            result = ValidationResult(false, result.errors + message)
        }
    }
}

// 使用示例
fun main() {
    val password = "secret123"
    
    val validation = password.validate {
        notEmpty()
        minLength(8)
        maxLength(20)
        matches(Regex(".*[0-9].*"), "必须包含数字")
        matches(Regex(".*[A-Z].*"), "必须包含大写字母") // 这个会失败
    }
    
    if (validation.isValid) {
        println("密码有效")
    } else {
        println("密码无效,原因:")
        validation.errors.forEach { println("- $it") }
    }
    /* 输出:
    密码无效,原因:
    - 必须包含大写字母
    */
}

四、扩展函数与属性的最佳实践

4.1 设计原则

单一职责:每个扩展函数只做一件事

命名清晰:函数名应准确表达其功能

避免滥用:不是所有工具函数都适合做成扩展

文档完善:为非直观的扩展添加KDoc
4.2 实用技巧

4.2.1 链式调用设计

复制代码
// 链式构建器风格
class StringBuilder {
    private val builder = StringBuilder()
    
    fun append(text: String): StringBuilder {
        builder.append(text)
        return this
    }
    
    fun appendLine(text: String = ""): StringBuilder {
        builder.appendLine(text)
        return this
    }
    
    override fun toString(): String = builder.toString()
}

// 扩展函数支持链式调用
fun StringBuilder.bold(): StringBuilder {
    return append("<b>").append(this.toString()).append("</b>")
}

fun main() {
    val result = StringBuilder()
        .append("Hello")
        .appendLine(", Kotlin!")
        .appendLine("This is bold:")
        .bold()
    
    println(result)
}

4.2 性能考虑

扩展函数是静态解析的,没有运行时开销

对于频繁调用的扩展,考虑内联(inline)优化

扩展属性有轻微性能开销(每次访问都会调用getter)

复制代码
// 内联扩展函数示例
inline fun <T> Iterable<T>.sumByLong(selector: (T) -> Long): Long {
    var sum = 0L
    for (element in this) {
        sum += selector(element)
    }
    return sum
}

五、总结与进阶方向

5.1 核心要点回顾

扩展函数和属性是静态解析的,不会影响原有类的实例

扩展函数可以定义在顶层、类内部或对象中

扩展属性不能有幕后字段(backing field)

可空接收者扩展可以安全处理null值
5.2 扩展函数 vs 成员函数

5.3 进阶学习方向

探索Kotlin标准库中的常用扩展(如also, apply, let等)

研究扩展函数在Android开发中的应用(如View绑定)

学习如何为第三方库编写扩展函数

实践用扩展函数构建领域特定语言(DSL)

相关推荐
油丶酸萝卜别吃5 小时前
utils.js 说明文档
开发语言·javascript·ecmascript
leisoo80977 小时前
100GBA股股票数据怎么存ClickHouseRedisMySQLJSON完整对比
大数据·linux·服务器·开发语言·python
WangYan20228 小时前
基于XGBoost与AI的生态—地学多源数据建模:植被与土地利用识别、土壤碳氮空间预测、生物多样性驱动机制、土壤微生物功能预测、生态退化与风险识别
python·机器学习·xgboost
不会代码的小猴8 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
一只旭宝9 小时前
细讲C加加【9】C++ std::function与std::bind详解|仿函数、绑定器、类成员绑定、占位符、成员偏移指针
开发语言·c++·算法
金銀銅鐵10 小时前
[Python] 借助 turtle 逐字展示唐诗《金缕衣》
python
coder!mq11 小时前
说几个常见的语法糖?
java·开发语言·算法
gugucoding11 小时前
38. 【Java】Stream API(下):高级操作与性能
java·开发语言
Lhan.zzZ11 小时前
在 Visual Studio 2022 中打造可扩展的动态链接库模块:从零搭建到原理解析
开发语言·c++·visual studio
心平气和量大福大12 小时前
android-实例-蒲公英-更新与安装-5-签名与生成APK
android·java·开发语言