为什么以及什么时候“隐含”需要

时间:2018-05-30 20:59:59

标签: scala

我正在尝试理解“隐式”操作的使用:

class foo {
  def x : Int = 12
}

object foo {
  implicit def intToFoo(x : Int ) : foo = new foo
}

object bar {
   implicitly[foo](1).x
}

以上编译。但我无法弄清楚为什么需要“隐式”操作。在我看来,因为'目标伴随对象'包含隐式转换,它应该自动发生。

2 个答案:

答案 0 :(得分:2)

implicitly(我已经看到)的一个常见用途是使用context bound类型参数。

回想一下,类型参数可以通过要求"证据来限制类型类:

def f[N](n :N)(implicit ev :Numeric[N]) :Boolean = ???

使用上下文绑定语法可以使其更清晰。

def f[N :Numeric](n: N) :Boolean = ???

但是现在我们没有使用隐式参数ev来处理。这不是一个问题。通常您需要类型限制,但您不需要证据参数。但是如果你确实需要这个参数,那么解决问题的方法就是通过implicitly将其拉入。

def f[N :Numeric](n: N) :Boolean = {
  val nn = implicitly[Numeric[N]].negate(n)
  . . .
}

这会增加一些开销,因为隐式被解析两次,一次作为(现在隐藏)隐式参数再次通过implicitly,但如果你想要干净的上下文绑定语法,只需要隐式参数一次或两次,有时被认为是值得的权衡。

答案 1 :(得分:1)

这里并不是真的需要它。你也可以逃脱

object bar {
   import foo._
   1.x
}

因为导入foo._也会将隐式转换带入隐式范围,因此1会自动包装到foo中,从而获得"方法x

在您的代码中使用implicitly是相当罕见的,因为它实际上只是类型归属的替代:

object bar {
   (1: foo).x
}

类型归属也有效,因为现在您再次提到您希望1foo类型,因此编译器将在foo的隐式范围内搜索适当的隐式转换。

即使您没有导入任何隐式转化,您的代码也不会以任何重要方式依赖implicitly。任何需要foo的其他函数都会发生同样的情况:     import scala.language.implicitConversions

class foo {
  def x : Int = 12
}

object foo {
  implicit def intToFoo(x : Int ) : foo = new foo
}

def randomOtherFunction(a: foo, i: Int): foo = a

object bar {
  randomOtherFunction(1, 42).x
}

此处,就像您在implicitly的示例中一样,函数randomOtherFunction需要foo作为第一个参数。由于Int不是foo,编译器会继续搜索从Intfoo的适用隐式转换。它看起来的一个地方是foo的伴侣对象。因此,编译器会插入intToFoo

  randomOtherFunction(intToFoo(1), 42).x

并且一切都在编译。