Kotlin中的infix关键字允许使用中缀表示法调用函数,使代码更简洁、可读性更高。
基本概念
infix关键字用于将函数标记为可以使用中缀表示法调用(省略点号和括号)。
使用条件:
- 必须是成员函数或扩展函数
- 必须只有一个参数
- 参数不能是可变参数(vararg)
- 参数不能有默认值
基本语法
infix fun 类型.函数名(参数: 参数类型): 返回类型 {
// 函数体
}
示例
1. 创建自定义中缀函数
class Person(val name: String) {
// 中缀函数
infix fun marry(spouse: Person) {
println("$name 和 ${spouse.name} 结婚了!")
}
}
fun main() {
val alice = Person("Alice")
val bob = Person("Bob")
// 使用中缀表示法
alice marry bob // 输出:Alice 和 Bob 结婚了!
// 等价于普通调用
alice.marry(bob)
}
2. 扩展函数中使用中缀
infix fun Int.add(x: Int): Int = this + x
infix fun String.concat(other: String): String = "$this $other"
fun main() {
val result1 = 5 add 3 // 8
val result2 = "Hello" concat "World" // "Hello World"
println(result1)
println(result2)
}
3. DSL(领域特定语言)应用
infix fun String.shouldBe(expected: String) {
if (this == expected) {
println("测试通过:$this == $expected")
} else {
println("测试失败:$this != $expected")
}
}
fun main() {
"Kotlin" shouldBe "Kotlin" // 测试通过
"Java" shouldBe "Kotlin" // 测试失败
}
Kotlin标准库中的中缀函数
Kotlin标准库已经提供了多个有用的中缀函数:
1. to 函数(创建Pair)
val pair = "name" to "John"
// 等价于
val pair2 = Pair("name", "John")
2. 区间操作
val range = 1..10
// 等价于
val range2 = 1.rangeTo(10)
val charRange = 'a'..'z'
3. 位运算
val flags = 0b0010
val result1 = flags shl 2 // 左移2位
val result2 = flags shr 1 // 右移1位
val result3 = flags and 0b0001 // 与运算
实际应用示例
1. 构建查询DSL
class Query {
private val conditions = mutableListOf<String>()
infix fun where(condition: String) {
conditions.add(condition)
}
infix fun and(condition: String) {
conditions.add("AND $condition")
}
infix fun or(condition: String) {
conditions.add("OR $condition")
}
override fun toString(): String {
return "SELECT * FROM users WHERE " + conditions.joinToString(" ")
}
}
fun query(init: Query.() -> Unit): Query {
val query = Query()
query.init()
return query
}
fun main() {
val q = query {
where "age > 18"
and "country = 'US'"
or "status = 'active'"
}
println(q) // SELECT * FROM users WHERE age > 18 AND country = 'US' OR status = 'active'
}
2. 数学表达式
data class Vector(val x: Int, val y: Int) {
infix fun dot(other: Vector): Int {
return this.x * other.x + this.y * other.y
}
infix fun cross(other: Vector): Int {
return this.x * other.y - this.y * other.x
}
}
fun main() {
val v1 = Vector(1, 2)
val v2 = Vector(3, 4)
val dotProduct = v1 dot v2 // 11
val crossProduct = v1 cross v2 // -2
println("点积: $dotProduct")
println("叉积: $crossProduct")
}
3. 配置构建器
class Configuration {
var host: String = "localhost"
var port: Int = 8080
var timeout: Int = 30
override fun toString(): String {
return "Configuration(host='$host', port=$port, timeout=$timeout)"
}
}
infix fun String.toHostOf(config: Configuration) {
config.host = this
}
infix fun Int.toPortOf(config: Configuration) {
config.port = this
}
fun configure(block: Configuration.() -> Unit): Configuration {
val config = Configuration()
config.block()
return config
}
fun main() {
val config = configure {
"api.example.com" toHostOf this
443 toPortOf this
timeout = 60
}
println(config)
}
注意事项
-
优先级:中缀函数调用比布尔操作符
&&和||、is和in检测等具有更低的优先级if (a && b isType c) // 先执行 b isType c,再与a进行&&运算 -
可读性:虽然中缀表示法可以使代码更简洁,但过度使用可能会降低代码的可读性
-
清晰性:确保函数名和参数类型能清晰地表达意图
最佳实践
- 当函数表示两个对象之间的关系时使用中缀表示法
- 为DSL设计时特别有用
- 保持函数名简洁且具有描述性
- 避免在复杂表达式中过度使用中缀表示法
总结
infix关键字是Kotlin提供的一个强大特性,它:
- 使代码更简洁、更易读
- 特别适合创建DSL
- 在数学表达式、集合操作等场景中非常有用
- 需要谨慎使用,确保代码可读性
通过合理使用infix函数,你可以创建出更加优雅和表达性强的Kotlin代码。