对于非重载和重载的方法,Scala从"Magnet Pattern“解析隐式转换的方式有很大的不同。
假设有如下实现的特征Apply
(“磁体模式”的变体)。
trait Apply[A] {
def apply(): A
}
object Apply {
implicit def fromLazyVal[A](v: => A): Apply[A] = new Apply[A] {
def apply(): A = v
}
}
现在,我们创建了一个特征Foo
,它有一个带有Apply
实例的apply
,因此我们可以向它传递任意类型A
的任何值,因为存在从A => Apply[A]
的隐式转换。
trait Foo[A] {
def apply(a: Apply[A]): A = a()
}
我们可以使用REPL和this workaround to de-sugar Scala code来确保它像预期的那样工作。
scala> val foo = new Foo[String]{}
foo: Foo[String] = $anon$1@3a248e6a
scala> showCode(reify { foo { "foo" } }.tree)
res9: String =
$line21$read.foo.apply(
$read.INSTANCE.Apply.fromLazyVal("foo")
)
这很有效,但是假设我们将一个复杂的表达式(带有;
)传递给apply
方法。
scala> val foo = new Foo[Int]{}
foo: Foo[Int] = $anon$1@5645b124
scala> var i = 0
i: Int = 0
scala> showCode(reify { foo { i = i + 1; i } }.tree)
res10: String =
$line23$read.foo.apply({
$line24$read.`i_=`($line24$read.i.+(1));
$read.INSTANCE.Apply.fromLazyVal($line24$read.i)
})
正如我们所看到的,隐式转换只应用于复杂表达式的最后一部分(即i
),而不是整个表达式。因此,在我们将i = i + 1
传递给apply
方法时,它的计算是严格的,这并不是我们所期望的。
好消息(或坏消息)。我们可以使scalac
在隐式转换中使用整个表达式。因此,i = i + 1
将像预期的那样缓慢地进行评估。为了做到这一点,我们(出人意料,出人意料!)我们添加了一个重载方法Foo.apply
,它接受任何类型,但不接受Apply
。
trait Foo[A] {
def apply(a: Apply[A]): A = a()
def apply(s: Symbol): Foo[A] = this
}
然后。
scala> var i = 0
i: Int = 0
scala> val foo = new Foo[Int]{}
foo: Foo[Int] = $anon$1@3ff00018
scala> showCode(reify { foo { i = i + 1; i } }.tree)
res11: String =
$line28$read.foo.apply($read.INSTANCE.Apply.fromLazyVal({
$line27$read.`i_=`($line27$read.i.+(1));
$line27$read.i
}))
正如我们所看到的,整个表达式i = i + 1; i
如预期的那样在隐式转换下完成。
所以我的问题是为什么会这样呢?为什么应用隐式转换的作用域取决于类中是否存在重载方法。
https://stackoverflow.com/questions/32064375
复制相似问题