Scala编译器如何解析隐式转换

时间:2016-01-05 08:33:59

标签: scala

昨天我遇到了隐式转换的问题。将其纳入导入范围:

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")

1 个答案:

答案 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。这不是隐式查找或隐式范围的问题,而是导入成员的阴影/隐藏问题。