Scala类型(不)相等的隐式解析:重载方法编译歧义问题
Scala重载方法因隐式参数导致编译歧义的原因
问题代码
import shapeless._ // =:! class G[T1] { def as[T2](implicit ev: T1 =:= T2): Unit = ??? def as[T2](implicit ev: T1 =:!= T2): Unit = ??? } val g = new G[Int] g.as[Int]
编译错误信息
ambiguous reference to overloaded definition, both method as in class G of type (implicit ev: Int =:!= Int): Unit and method as in class G of type (implicit ev: Int =:= Int): Unit match expected type ? g.as[Int]
原因解析
这是因为Scala编译器处理重载方法时,优先检查方法参数列表的“结构特征”是否能区分重载,而非先验证隐式参数是否可推导。
当调用g.as[Int]时,编译器看到两个as方法的签名:一个需要T1 =:= T2的隐式实例,另一个需要T1 =:!= T2的隐式实例。虽然这两个隐式参数的类型逻辑上互斥,但编译器在重载解析的早期阶段,并不会去判断Int =:= Int或Int =:!= Int的隐式实例是否存在,而是先对比方法的重载特征——这两个方法的参数列表结构完全一致(都是单个隐式参数,参数类型为类型类),因此编译器会判定这两个方法的重载存在歧义,直接抛出错误,不会进入后续的隐式参数查找阶段。
换句话说,哪怕其中一个隐式参数实际上根本无法生成实例(比如Int =:!= Int的实例不存在),编译器也不会在重载解析环节考虑这一点,只会因为参数结构相似判定为歧义。
内容的提问来源于stack exchange,提问作者Kamil Kloch
相关产品推荐
相关产品推荐

