Kotlin扩展函数解析疑问:AnInterfaceImpl实例调用f方法为何解析至AnObject中的扩展函数
AnInterfaceImpl().f("hi")会解析到AnObject中的扩展函数? 先看你的代码和运行结果:
package experimental import experimental.AnObject.f interface AnInterface { fun String.a() = "[AnInterface] $this" } object AnObject { fun AnInterface.f(str: String) = "[AnObject]" + str.a() } class AnInterfaceImpl : AnInterface fun main() { println( AnInterfaceImpl().f("hi") ) }
运行结果为:[AnObject][AnInterface] hi
你的疑问是:为什么AnInterfaceImpl().f("hi")最终会调用到AnObject里定义的扩展函数?
咱们一步步拆解关键逻辑,就能搞懂这个问题:
1. 导入语句让扩展函数变得可见
代码开头的import experimental.AnObject.f是核心前提之一——它把AnObject内部定义的扩展函数f直接导入到了当前代码的作用域中。这意味着在main函数里,当你尝试调用f时,这个导入的函数是编译器会考虑的候选选项。
2. 扩展函数的接收者匹配规则
AnObject里的f是以AnInterface为接收者的扩展函数,定义形式是:
fun AnInterface.f(str: String) = "[AnObject]" + str.a()
简单来说,任何实现了AnInterface的类的实例(包括AnInterfaceImpl这种子类实例),都具备调用这个扩展函数的资格——因为AnInterfaceImpl是AnInterface的实现类,它的实例属于AnInterface类型体系。
3. 编译器的函数解析优先级
当你调用AnInterfaceImpl().f("hi")时,编译器会按顺序寻找匹配的函数:
- 首先检查
AnInterfaceImpl和它的父类AnInterface有没有名为f的成员函数——很明显,两者都没有定义; - 接着检查当前作用域中可见的扩展函数:导入的
AnObject.f正好满足:接收者是AnInterface类型(AnInterfaceImpl实例符合),参数是String(传入的"hi"匹配),完全符合调用签名,所以编译器就选中了这个扩展函数。
4. 扩展函数的静态绑定特性
这里补充个Kotlin扩展函数的特性:扩展函数是静态解析的,也就是说编译器是根据调用者的静态类型(而不是运行时类型)来决定使用哪个扩展函数。这里AnInterfaceImpl()的静态类型是AnInterfaceImpl,但它是AnInterface的子类,所以依然能匹配到接收者为AnInterface的扩展函数。
如果你把import experimental.AnObject.f这行删掉,编译器会直接报错找不到f函数,这也能反过来证明,正是这个导入的扩展函数在起作用。
内容的提问来源于stack exchange,提问作者David Soroko

