2017-10-09 72 views
0
% 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的类型推断的重载方法失败,尽管不冲突的签名

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

scalac有时无法找到正确的含义或者推理出合适的类型,如果将含义与超载混合在一起。

在这个主题上有几个杰拉门票,这个特殊的门票:SI-9523,似乎是问题中的问题。

在你的情况scalac不能当~~~超载推断类型参数swap,所以用swap[Int, String]标注它应该工作。

重载一般不提倡Scala中(见Why "avoid method overloading"?)和(http://www.wartremover.org/doc/warts.html),所以最好的解决方法是,以避免过载。

+0

好的。所以这是一个(nother)斯卡拉bug :) –

+0

实际上,这是一般重载的限制,而不是与implicits有关的错误。通过让它选择适当的重载*和*一次性推断“swap”方法的类型参数,您会问到编译器太多了。在关于重载解析和本地类型推断的段落中有[specced](https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#overloading-resolution)。 –