搜索隐式转换时,Scala是否使用目标类型?

时间:2014-03-12 22:17:37

标签: scala implicit-conversion implicit scala-2.11

我正在读这本书 Scala in Depth ,第5章关于implicits。作者在第102页说明了这一点:

  

隐式视图使用的隐式作用域与隐式参数相同。但是当编译器正在寻找类型关联时,它会使用它试图从 [我的强调]转换 的类型,而不是它试图转换为的类型。

然而,几页之后,他展示了一个示例,其中包含complexmath.ComplexNumber类。您导入i ComplexNumber,并将其称为*方法,该方法采用ComplexNumber参数。

import complexmath.i
i * 1.0

要将1.0转换为ComplexNumber,会找到一个如此定义的隐式转换:

package object complexmath {
  implicit def realToComplex(r: Double) = new ComplexNumber(r, 0)
  val i = ComplexNumber(0, 1)    

但这与第一个陈述相矛盾,不是吗?它需要找到Double => ComplexNumber。为什么它会在complexmath包中查找,这是[{1}}的隐式范围的一部分,而不是ComplexNumber的隐式范围的一部分?

4 个答案:

答案 0 :(得分:2)

规范说明了观点:

隐式范围是T =>之一。角

,即Function[T, pt],因此隐式范围包括与Tpt相关联的类,转换的来源和目标。

scala> :pa
// Entering paste mode (ctrl-D to finish)

class B
class A
object A { implicit def x(a: A): B = new B }

// Exiting paste mode, now interpreting.

warning: there were 1 feature warning(s); re-run with -feature for details
defined class B
defined class A
defined object A

scala> val b: B = new A
b: B = B@63b41a65

scala> def f(b: B) = 3 ; def g = f(new A)
f: (b: B)Int
g: Int

scala> :pa
// Entering paste mode (ctrl-D to finish)

class A
class B
object B { implicit def x(a: A): B = new B }

// Exiting paste mode, now interpreting.

scala> val b: B = new A
b: B = B@6ba3b481

答案 1 :(得分:1)

我认为你误解了他的文字。

编译器将在所有可用范围中查找隐式转换,直到找到合适的范围。

在您指定的示例中,我们会发现 complexmath 包提供了一个。

然而,合适的定义是'我们感兴趣的是这里。在隐式转换的情况下,编译器将寻找从 * Double *到预期类型 ComplexNumber 的转换

换句话说,它会检查所有转化来自 * Double *,直到找到可以将 Double 转换为目标类型。

作者Josh并不是说编译器需要在与 Double 对象关联的对象中定义转换。转换可以在任何地方定义。

在这种特殊情况下,转换是在与 ComplexNumber 对象关联的包对象中定义的。这是正常的,是“想要'的ComplexNumber对象”。与 Double 兼容。

由于使用意味着导入 ComplexNumber ,因此导入包' complexmath ',转换将始终在范围内。

答案 2 :(得分:1)

所以这更多是关于编译器已经*知道关于表达式的内容。

您在示例中有:

import complexmath.i
i * 1.0

编译器以此开头:

1)我有i的类型,它是Complex 2)我在i上有一个名为*的方法,它采用Complex类型的参数 3)你传给我一个Int,但我需要一个Complex。让我们看看我是否有隐含的东西给了我。

此示例有效,因为*方法是在Complex上定义的。

希望有所帮助!

答案 3 :(得分:0)

源或目标都有效:

object Foo {
  implicit def bar(b: Bar): Foo = new Foo {}
  implicit def foo(f: Foo): Bar = new Bar {}
}
trait Foo
trait Bar

implicitly[Foo => Bar]  // ok
implicitly[Bar => Foo]  // ok

val b = new Bar {}
val bf: Foo = b  // ok
val f = new Foo {}
val fb: Bar = f  // ok

所以我觉得这句话错了(?)