Kotlin中将lambda替换为方法引用报Unresolved reference的原因
问题描述
在如下示例中,IntelliJ会提示将main函数第一行被注释的lambda表达式,替换为main函数第二行所示的方法引用写法。
fun Int.matches1(n: Int): Boolean = TODO() fun Int.matches2(n: Int): Boolean = TODO() fun main() { // val matches: Int.(Int) -> Boolean = { n -> matches1(n) } val matches: Int.(Int) -> Boolean = ::matches1 }
使用lambda表达式的代码行可正常编译运行,但改用方法引用写法时,Kotlin编译器会抛出Unresolved reference: matches1的编译错误。
产生原因
这个问题是IDE的错误提示+Kotlin语法解析规则差异共同导致的:
- lambda版本能正常编译,是因为
Int.(Int) -> Boolean属于带接收者的函数类型,对应lambda内部的隐式接收者this就是Int类型,lambda中写的matches1(n)等价于this.matches1(n),编译器可以准确定位到定义在Int上的扩展函数matches1,不会出现解析问题。 - 直接写
::matches1属于未限定的顶层方法引用,编译器只会在当前作用域查找顶层无接收者函数、当前上下文的成员函数中名为matches1的定义,不会自动将其关联为Int的扩展函数引用。由于matches1是Int的扩展函数,不属于顶层无接收者函数范畴,编译器找不到对应定义,自然抛出未解析引用的错误。 - 该场景下正确的方法引用写法需要显式指定接收者所属类型,即写为
Int::matches1,替换后代码可正常编译,与原lambda写法的语义完全等价。
本质上是IntelliJ的这个快速替换逻辑没有覆盖扩展方法引用的解析规则,给出了错误的修改建议,才会出现按提示改完反而编译失败的情况。
内容的提问来源于stack exchange,提问作者k314159
相关产品推荐
相关产品推荐

