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 分钟前
C++之路:类基础、构造析构、拷贝构造函数
linux·开发语言·c++
Ting-yu9 分钟前
Java中Stream流的使用
java·开发语言·windows
【ql君】qlexcel38 分钟前
Notepad++ 复制宏、编辑宏的方法
开发语言·javascript·notepad++··宏编辑·宏复制
Zevalin爱灰灰1 小时前
MATLAB GUI界面设计 第六章——常用库中的其它组件
开发语言·ui·matlab
冰糖猕猴桃1 小时前
【Python】进阶 - 数据结构与算法
开发语言·数据结构·python·算法·时间复杂度、空间复杂度·树、二叉树·堆、图
天水幼麟1 小时前
python学习笔记(深度学习)
笔记·python·学习
巴里巴气1 小时前
安装GPU版本的Pytorch
人工智能·pytorch·python
wt_cs1 小时前
银行回单ocr api集成解析-图像文字识别-文字识别技术
开发语言·python
_WndProc2 小时前
【Python】Flask网页
开发语言·python·flask
互联网搬砖老肖2 小时前
Python 中如何使用 Conda 管理版本和创建 Django 项目
python·django·conda