Infix Function(中缀函数)
1. 中缀函数(Infix Function)
核心定义
用infix关键字修饰的函数,支持「省略点号和括号」的中缀调用语法(a func b),本质是一种语法糖。
关键特征
- 必须是成员函数或扩展函数(不能是顶层函数);
- 必须只有一个参数,且参数不能有默认值;
- 调用时可省略点号和括号,用空格分隔调用者和参数,代码更简洁直观。
使用场景
适合表达「二元关系」的操作(如关联、匹配、运算、判断等),让代码更接近自然语言。
示例
// 示例1:扩展函数实现中缀函数(判断字符串是否以指定后缀结尾)
infix fun String.endsWithSuffix(suffix: String): Boolean {
return this.endsWith(suffix)
}
// 示例2:成员函数实现中缀函数(自定义计算器加法)
class Calculator(val base: Int) {
infix fun add(num: Int): Int {
return base + num
}
}
// 使用
fun main() {
// 中缀调用扩展函数
val str = "HelloKotlin"
println(str endsWithSuffix "Kotlin") // true(等价于str.endsWithSuffix("Kotlin"))
// 中缀调用成员函数
val calc = Calculator(10)
println(calc add 20) // 30(等价于calc.add(20))
}
注意事项
- 中缀函数的优先级低于算术运算符、逻辑运算符,高于赋值运算符;
- 避免滥用,仅在能提升代码可读性的二元关系场景使用。
中缀函数
扩展函数可以采用中缀函数的使用方式,但需要同时满足中缀函数的相关约束条件;中缀函数和扩展函数并非互斥概念,而是从两个不同维度对函数的分类。
- 中缀函数是「调用语法」特殊,扩展函数是「功能扩展」机制,二者不互斥、可叠加;
- 扩展函数可以用中缀方式调用,只需满足中缀函数的 4 个核心约束;
- 中缀函数的核心价值是简化二元关系操作的代码,扩展函数的核心价值是无侵入式扩展已有类功能;
- 中缀函数的两种存在形式:类成员函数、扩展函数(均需满足约束条件)。
中缀函数 vs 扩展函数:核心区别(维度不同)
两者的核心差异在于分类维度不同,这是理解两者关系的关键:
| 对比维度 | 中缀函数(Infix Function) | 扩展函数(Extension Function) |
|---|---|---|
| 核心定义 | 一种函数调用语法的特殊形式,允许省略括号和点号,以更简洁的方式调用函数 | 一种函数功能扩展的机制,允许在不修改原有类源码的前提下,为该类添加新的成员函数 |
| 分类维度 | 从「函数的调用方式」维度划分 | 从「函数的归属 / 扩展能力」维度划分 |
| 核心价值 | 简化函数调用,让代码更具可读性(尤其适合二元关系操作,如关联、匹配等) | 扩展已有类的功能,避免继承的冗余,符合「开闭原则」 |
| 存在形式 | 可作为类的成员函数,也可作为扩展函数(满足约束即可) | 可作为普通扩展函数,也可升级为中缀扩展函数(满足约束即可) |
中缀函数的必备约束条件(无论是否为扩展函数)
要使用中缀语法调用函数,必须满足以下4 个严格约束,缺一不可:
- 必须是成员函数或扩展函数:普通的顶层函数(不属于任何类、也不是扩展函数)无法被声明为中缀函数;
- 必须只有一个参数:函数的参数列表中只能有一个参数,不能无参,也不能有多个参数;
- 参数不能有默认值:该唯一参数不允许指定默认值(避免调用时的歧义);
- 必须用
infix关键字修饰:在函数声明前显式添加infix关键字,标记该函数支持中缀调用语法。
扩展函数使用中缀调用方式的示例(可行)
下面通过代码示例,展示如何将扩展函数声明为中缀函数,并用中缀语法调用:
// 1. 定义:扩展函数 + 中缀函数(满足所有中缀约束)
// 为 String 类扩展一个中缀函数,用于判断字符串是否以指定后缀结尾(简化版 endsWith)
infix fun String.endsWithSuffix(suffix: String): Boolean {
return this.endsWith(suffix)
}
// 2. 调用方式对比
fun main() {
val str = "HelloKotlin"
val suffix = "Kotlin"
// 方式1:普通扩展函数调用方式(点号+括号)
val result1 = str.endsWithSuffix(suffix)
println("普通调用结果:$result1") // 输出:普通调用结果:true
// 方式2:中缀函数调用方式(省略点号和括号,直接用空格分隔)
val result2 = str endsWithSuffix suffix
println("中缀调用结果:$result2") // 输出:中缀调用结果:true
}
再举一个更典型的二元关系示例(集合关联):
// 为 List<Int> 扩展中缀函数,实现与另一个 List<String> 按索引关联
infix fun List<Int>.associateWithList(strList: List<String>): Map<Int, String> {
val resultMap = mutableMapOf<Int, String>()
for (i in indices) {
if (i < strList.size) {
resultMap[this[i]] = strList[i]
}
}
return resultMap
}
fun main() {
val nums = listOf(1, 2, 3)
val words = listOf("A", "B", "C")
// 中缀调用扩展函数,代码更简洁直观
val associateMap = nums associateWithList words
println(associateMap) // 输出:{1=A, 2=B, 3=C}
}
非扩展函数的中缀函数(类成员函数)
为了完整理解,这里给出类成员函数作为中缀函数的示例(对比扩展函数):
// 定义一个简单的类
class Calculator(val base: Int) {
// 类成员函数声明为中缀函数(满足约束:单个参数、无默认值、infix修饰)
infix fun add(num: Int): Int {
return base + num
}
}
fun main() {
val calc = Calculator(10)
// 中缀调用类成员函数
val result = calc add 20
println(result) // 输出:30
// 等价于普通调用
val result2 = calc.add(20)
println(result2) // 输出:30
}