尽管签名没有冲突,Scala类型推断在重载方法上失败

时间:2017-10-09 17:38:10

标签: scala types type-inference

% scala                                                                     
Welcome to Scala 2.12.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.

scala>   trait Op[-Y, -Z, +A, +B] {
     |     def apply(other: (Y, Z)): (A, B)
     |   }
defined trait Op

scala>   implicit class RichTuple2[+A, +B](t: (A, B)) {
     |     def ~~~(other: Int): (A, B) = ???
     |     def ~~~[RA, RB](other: Op[A, B, RA, RB]): (RA, RB) = other.apply(t)
     |   }
defined class RichTuple2

scala>   def swap[A, B] = new Op[A, B, B, A] {
     |     override def apply(other: (A, B)) = (other._2, other._1)
     |   }
swap: [A, B]=> Op[A,B,B,A]

scala> (1, "foo") ~~~ swap
<console>:14: error: overloaded method value ~~~ with alternatives:
  [RA, RB](other: Op[Int,String,RA,RB])(RA, RB) <and>
  (other: Int)(Int, String)
 cannot be applied to (Op[Nothing,Nothing,Nothing,Nothing])
       (1, "foo") ~~~ swap

如果我删除了第一个~~~(other: Int)方法,那么它可以工作:

scala>   trait Op[-Y, -Z, +A, +B] {
     |     def apply(other: (Y, Z)): (A, B)
     |   }
defined trait Op

scala>   implicit class RichTuple2[+A, +B](t: (A, B)) {
     |     def ~~~[RA, RB](other: Op[A, B, RA, RB]): (RA, RB) = other.apply(t)
     |   }
defined class RichTuple2

scala>   def swap[A, B] = new Op[A, B, B, A] {
     |     override def apply(other: (A, B)) = (other._2, other._1)
     |   }
swap: [A, B]=> Op[A,B,B,A]

scala> (1, "foo") ~~~ swap
res0: (String, Int) = (foo,1)

问题是为什么在这种情况下类型推断和方法选择失败?方法~~~(other: Int)采用的参数根本不与swap的类型相关(具有Op类型)。有人知道解决方法吗?

1 个答案:

答案 0 :(得分:1)

scalac有时难以找到正确的含义,或者当一个混合带有重载的含义时推断出正确的类型。

这个主题有几张jira门票,而这个特别的门票SI-9523似乎与你问题中的问题相同。

在您的情况下,当swap重载时,scalac无法推断~~~的类型参数,因此使用swap[Int, String]对其进行注释应该有效。

在Scala(请参阅Why "avoid method overloading"?)和(http://www.wartremover.org/doc/warts.html)中通常不鼓励重载,因此最好的解决方案是避免重载。