Scala的隐式类转换的范围

时间:2012-05-23 20:42:11

标签: scala implicit-conversion

Scala似乎在最大可能表达式上应用隐式类转换,如下例所示:

scala> class B { def b = { println("bb"); true } }
defined class B

scala> class A { def a = { println("aa"); new B } }
defined class A

scala> (new A).a.b
aa
bb
res16: Boolean = true

scala> class XXX(b: => Boolean) { def xxx = 42 }
defined class XXX

scala> implicit def toXXX(b: => Boolean) = new XXX(b)
toXXX: (b: => Boolean)XXX

scala> (new A).a.b.xxx
res18: Int = 42

我对这个事实感到非常高兴,但我的问题是SLS的哪一部分指定了这种行为?例如,为什么它不首先评估(new A).a.btrue,只是对该值应用转换?

2 个答案:

答案 0 :(得分:0)

包含隐式转化

的行
(new A).a.b.xxx

由编译器(即在编译时)转换为

toXXX((new A).a.b).xxx

如果您在启动Scala时使用-Xprint:typer选项,我们可以看到这一点。

private[this] val res3: Int = $line5.$read.$iw.$iw.toXXX(new $line2.$read.$iw.$iw.A().a.b).xxx;

由于此转换发生在编译时而非运行时,因此在应用转换之前,Scala无法将(new A).a.b评估为true。因此,您获得的行为与您刚刚编写toXXX((new A).a.b).xxx的行为完全相同。

答案 1 :(得分:0)

正如Ryan Hendrickson在邮件列表中的回答:

[您要查找的定义]在7.3节中,在应用了视图的三种情况的列表中:

  1. 如果选择器不表示成员,则选择e.m,其中e为T类型 在这种情况下,搜索适用于e及其结果的视图v 包含一个名为m的成员。搜索按照隐式的情况进行 参数,其中隐式范围是T的一个。如果找到这样的视图, 选择e.m转换为v(e).m。
  2. 因此编译器只能生成在语义上等同于v(e).m的东西,正如您所说,当涉及到名称参数时

    val x = e
    v(x).m
    

    在语义上不等同于v(e).m