Scala存在多歧义隐式时编译器选择规则及Fraction案例疑问
Scala隐式转换行为疑问解答
编译器隐式转换检查核心逻辑
针对a.方法(b)形式的调用(Scala中所有运算符本质都是方法调用),编译器的检查顺序如下:
- 首先确认左值
a本身是否存在对应名称的方法:- 若存在,仅尝试对入参
b做隐式转换,匹配方法的参数类型要求 - 若不存在,才会尝试对左值
a做隐式转换,查找转换后类型包含对应方法的隐式逻辑
- 若存在,仅尝试对入参
问题1:案例1中val a = 2 * Fraction(1,2)为什么调用fractionToDouble而非intToFraction?
该语句本质是2.*(Fraction(1,2)):
- 左值
2为Int类型,本身已经实现了*方法,且该方法支持接收Double类型的入参 - 当前传入的参数是Fraction类型,编译器会优先查找可将Fraction转换为Double的隐式方法,作用域内的
fractionToDouble完全符合要求,因此直接转换右值参与运算,不会触发左值2的隐式转换。
问题2:案例3中val c = Fraction(4,5) * 3为什么调用intToFraction而非fractionToDouble?
该语句本质是Fraction(4,5).*(3):
- 左值为Fraction类型,本身已经实现了
*方法,且该方法要求入参为Fraction类型 - 当前传入的参数是Int类型的
3,编译器会查找可将Int转换为Fraction的隐式方法,作用域内的intToFraction完全符合要求,因此直接转换右值参与运算。
关于猜想的纠正
不存在「优先转换右操作数」的通用规则,你观察到的现象本质是:只要左操作数本身存在对应名称的方法,编译器就不会尝试转换左操作数,只会尝试转换入参匹配方法要求。只有左操作数本身不存在对应方法/属性时,才会触发左操作数的隐式转换,比如案例2的2.den:Int类型没有den属性,编译器才会尝试将2转换为Fraction类型后再访问den。
内容的提问来源于stack exchange,提问作者Gunjan Shah
相关产品推荐
相关产品推荐

