为什么对模板类的两个成员执行+操作会导致类型不匹配错误



最近,出于性能原因,我决定将项目的代码库移植到Scala,但就在我刚开始的时候,我被一个我不理解的错误阻止了。这是导致错误的最小代码量:

class Foo[A](var x: A) {
def +(other: Foo[A]) = new Foo[A](this.x + other.x)
}

错误本身:

test.scala:2: error: type mismatch;
found   : A
required: String
def +(other: Foo[A]) = new Foo[A](this.x + other.x)
^

环顾四周,我在论坛上发现了一些关于类似错误的帖子,这些错误显然是由Scala将模板类型隐式转换为字符串(?(引起的。

如注释中所述,编译器没有足够的关于类型A的信息来了解如何+

出现令人困惑的错误消息的原因是编译器"知道"所有内容都有toString()方法,而类型String+方法。那么,为什么它不将两者一起转换为类型String+呢?这是因为AString的转换是一种隐式转换,编译器不会为了解析表达式而进行多个隐式转换。

因此CCD_ 10错误。编译器说:"为了解析+方法,我已经将第一个A转换为String,但现在我已经这样做了,我不能在第二个A元素上再这样做了。">


对此有几种不同的方法。这是一个。

class Foo[A:Numeric](var x: A) {
def +(other: Foo[A]) =
new Foo[A](implicitly[Numeric[A]].plus(this.x, other.x))
}

CCD_ 15仅限于在CCD_ 16类型类中找到的类型。要将两个A添加在一起,请将Numeric[A]的实现从隐式作用域中拉出,并调用其plus()方法。

这里的问题是this.x + other.x中的加号方法不是Foo[A]中定义的加号方法。它来自A。并且由于A仍然是未定义的,所以可以是Any。和往常一样,编译器将寻找一种方法来进行编译,在这种情况下,它将找到一个允许this.x调用+方法的转换。它会在范围内并具有的Predef.scala中找到这一点

implicit final class any2stringadd[A](private val self: A) extends AnyVal { def +(other: String): String = String.valueOf(self) + other }

因此,如果this.x是能够连接that.xString,那么它也应该是字符串。事实并非如此。

你可以办理入住手续https://github.com/scala/scala/blob/706ef1b291134a5e5bce2275df2c222261f73451/src/library/scala/Predef.scala#L381

最新更新