首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >磁体模式和重载方法

磁体模式和重载方法
EN

Stack Overflow用户
提问于 2015-08-18 13:42:57
回答 1查看 1.7K关注 0票数 19

对于非重载和重载的方法,Scala从"Magnet Pattern“解析隐式转换的方式有很大的不同。

假设有如下实现的特征Apply (“磁体模式”的变体)。

代码语言:javascript
复制
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]的隐式转换。

代码语言:javascript
复制
trait Foo[A] {
  def apply(a: Apply[A]): A = a()
}

我们可以使用REPL和this workaround to de-sugar Scala code来确保它像预期的那样工作。

代码语言:javascript
复制
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方法。

代码语言:javascript
复制
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

代码语言:javascript
复制
trait Foo[A] {
  def apply(a: Apply[A]): A = a()
  def apply(s: Symbol): Foo[A] = this
}

然后。

代码语言:javascript
复制
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如预期的那样在隐式转换下完成。

所以我的问题是为什么会这样呢?为什么应用隐式转换的作用域取决于类中是否存在重载方法。

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32064375

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档