昨天我遇到了隐式转换的问题。将其纳入导入范围:
object FooConversions {
implicit def toString(foo: Foo): String = foo.toString
}
给了我编译错误。花了一段时间才发现调用函数toString
是罪魁祸首。我没有花太多时间进一步调查,但我的猜测是它与Object中的toString方法发生冲突?编译器如何处理这样的隐式转换?
scala> case class Foo(name: String)
defined class Foo
scala> object FooConversions {
| implicit def toString(foo: Foo): String = foo.toString
| }
defined object FooConversions
scala> import FooConversions._
import FooConversions._
scala> val x: String = Foo("bob")
<console>:16: error: type mismatch;
found : Foo
required: String
val x: String = Foo("bob")
答案 0 :(得分:2)
这是由于成员阴影造成的。导入的toString
在您希望隐式转换发生的范围内不可用。让我们看看它是如何运作的......
首先让我们检查一下隐含的作用:
scala> object FooConversions {
| implicit def toString(foo: Foo): String = foo.toString
|
| val x: String = Foo("bob")
| }
defined object FooConversions
是的,它在原始/定义范围内。
现在让我们尝试查看导入的方法toString
是否可用:
object FooConversions {
implicit def toString(foo: Foo): String = foo.toString
}
import FooConversions._
val y: String = toString(Foo("bob"))
<console>:28: error: too many arguments for method toString: ()String
val y: String = toString(Foo("bob"))
它不可用 - 它被封闭物体的toString
遮挡。在REPL中编译Scala的代码将所有内容都放在一个魔术对象中。在现实生活中,代码将驻留在某个对象/类中。
尝试明确调用toString
以检查它是否可能有效:
scala> val y: String = FooConversions.toString(Foo("bob"))
y: String = Foo(bob)
显然没有问题。
因此,解决方案是(1)将toString
重命名为其他可能无法隐藏的名称:
scala> import scala.language.implicitConversions
import scala.language.implicitConversions
scala> case class Foo(name: String)
defined class Foo
scala> object FooConversions {
| implicit def toStr(foo: Foo): String = foo.toString
| }
defined object FooConversions
scala> import FooConversions._
import FooConversions._
scala> val x: String = Foo("bob")
x: String = Foo(bob)
或(2)重新定义一个隐含的(糟透了):
scala> import scala.language.implicitConversions
import scala.language.implicitConversions
scala> case class Foo(name: String)
defined class Foo
scala> object FooConversions {
| implicit def toString(foo: Foo): String = foo.toString
| }
defined object FooConversions
scala> implicit def toStr(foo: Foo) = FooConversions.toString(foo)
toStr: (foo: Foo)String
scala> val x: String = Foo("bob")
x: String = Foo(bob)
P.S。这不是隐式查找或隐式范围的问题,而是导入成员的阴影/隐藏问题。