Kotlin函数重载在类型协变下歧义但泛型下无歧义问题
Kotlin重载解析歧义问题分析
首先给出问题复现代码:
open class Parent class Child: Parent() fun <T: Parent> foo(obj: T): T = obj inline fun <T: Parent> foo(block: () -> T): T = foo(block()) fun <T> bar(obj: T): T = obj inline fun <T> bar(block: () -> T): T = bar(block()) fun main() { // 编译报错:重载解析歧义 foo { Child() } // 正常编译运行 bar { "something" } }
为什么foo { Child() }会触发歧义
核心原因和Kotlin重载解析的流程、泛型边界对优先级的影响有关:
- 重载解析的第一步会先收集所有参数数量匹配的候选,两个单参数的
foo重载都会进入候选列表。 - 对于接收函数类型的
foo(block: () -> T)重载:传入的{ Child() }是() -> Child类型,符合函数类型参数要求,泛型T推导为Child,满足<T: Parent>的边界约束,属于合法候选。 - 对于接收普通参数的
foo(obj: T)重载:由于该重载的泛型存在上界约束,Kotlin编译器的适配度计算逻辑会将该重载的优先级提升到和函数类型重载相同的水平。且重载解析的优先级判断在泛型边界校验之前完成,判定优先级相等的阶段不会先校验() -> Child是否满足<T: Parent>的约束,因此两个重载会被判为歧义。
为什么bar { "something" }无歧义
- 两个
bar重载同样会进入候选列表,但普通参数重载的泛型没有任何边界约束。 - Kotlin重载解析规则明确规定:当传入lambda字面量时,接收函数类型参数的重载,优先级高于无边界泛型普通参数的重载。因此编译器会直接选择
bar(block: () -> T)重载,不会触发歧义。
内容的提问来源于stack exchange,提问作者chriptus13
相关产品推荐
相关产品推荐

