Scala 为什么和什么时候是';隐式';必修的

Scala 为什么和什么时候是';隐式';必修的,scala,Scala,我试图理解“隐式”操作的用法: class foo { def x : Int = 12 } object foo { implicit def intToFoo(x : Int ) : foo = new foo } object bar { implicitly[foo](1).x } 以上内容汇编而成。但我不明白为什么需要“隐式”操作。在我看来,因为“目的地同伴对象”包含隐式转换,所以它应该自动发生。这里实际上不需要它。你也可以逃脱惩罚 object bar {

我试图理解“隐式”操作的用法:

class foo {
  def x : Int = 12
}

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

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

以上内容汇编而成。但我不明白为什么需要“隐式”操作。在我看来,因为“目的地同伴对象”包含隐式转换,所以它应该自动发生。

这里实际上不需要它。你也可以逃脱惩罚

object bar {
   import foo._
   1.x
}
因为导入
foo.\u
也会将隐式转换带入隐式范围,因此
1
将自动包装到
foo
中,从而“获取”方法
x

在代码中隐式地使用
是相当少见的,因为它本质上只是类型归属的替代:

object bar {
   (1: foo).x
}
类型归属也起作用,因为现在您再次提到,您希望
1
的类型为
foo
,因此编译器将在
foo
的隐式范围中搜索合适的隐式转换

即使不导入任何隐式转换,代码也不会以任何显著方式隐式依赖于
。需要
foo
的任何其他函数也会发生同样的情况: 导入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
}
这里,就像您隐式使用
的示例一样,
randomootherfunction
函数需要一个
foo
作为第一个参数。由于
Int
不是
foo
,编译器将继续搜索从
Int
foo
的适用隐式转换。它看起来的一个地方是
foo
的伴生对象。因此,编译器插入
intToFoo

  randomOtherFunction(intToFoo(1), 42).x

所有的东西都可以编译。

这里并不需要。你也可以逃脱惩罚

object bar {
   import foo._
   1.x
}
因为导入
foo.\u
也会将隐式转换带入隐式范围,因此
1
将自动包装到
foo
中,从而“获取”方法
x

在代码中隐式地使用
是相当少见的,因为它本质上只是类型归属的替代:

object bar {
   (1: foo).x
}
类型归属也起作用,因为现在您再次提到,您希望
1
的类型为
foo
,因此编译器将在
foo
的隐式范围中搜索合适的隐式转换

即使不导入任何隐式转换,代码也不会以任何显著方式隐式依赖于
。需要
foo
的任何其他函数也会发生同样的情况: 导入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
}
这里,就像您隐式使用
的示例一样,
randomootherfunction
函数需要一个
foo
作为第一个参数。由于
Int
不是
foo
,编译器将继续搜索从
Int
foo
的适用隐式转换。它看起来的一个地方是
foo
的伴生对象。因此,编译器插入
intToFoo

  randomOtherFunction(intToFoo(1), 42).x

一切都可以编译。

隐式
的一个更常见的用法是使用类型参数

回想一下,可以通过要求“证据”将类型参数限制为类型类:

通过使用上下文绑定语法,这可以变得更清晰

def f[N :Numeric](n: N) :Boolean = ???
但是现在我们没有隐式参数ev。这并不总是一个问题。通常需要类型限制,但不需要证据参数。但是如果您确实需要该参数,那么解决问题的一种方法是通过
隐式地将其拉入

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

这增加了一点开销,因为隐式被解析两次,一次作为(现在隐藏的)隐式参数,另一次通过
隐式
,但是如果您想要干净的上下文绑定语法,并且只需要隐式参数一两次,它有时被视为一种值得权衡的选择。

隐式地使用
的一个更常见的用法是使用类型参数

回想一下,可以通过要求“证据”将类型参数限制为类型类:

通过使用上下文绑定语法,这可以变得更清晰

def f[N :Numeric](n: N) :Boolean = ???
但是现在我们没有隐式参数ev。这并不总是一个问题。通常需要类型限制,但不需要证据参数。但是如果您确实需要该参数,那么解决问题的一种方法是通过
隐式地将其拉入

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

这增加了一点开销,因为隐式被解析两次,一次作为(现在隐藏的)隐式参数,另一次通过
隐式
,但是如果您想要干净的上下文绑定语法,并且只需要隐式参数一两次,它有时被视为一种值得权衡的选择。

我想我的问题是,为什么我必须显式导入foo.--既然它是目标类型的伴生对象,转换是否应该不自动在范围内?@MichaelWrighton
bar
foo
无关,为什么它应该在范围内?您要么必须导入foo.\uu
,要么必须引入某种带有参数列表的函数,该函数需要一个
foo
。否则,
bar
中的代码根本看不到
foo
,即使它对
1.x
没有任何意义。我想我的问题是,为什么我必须显式导入foo。因为它是目标类型的伴随对象,转换不应该自动在范围内吗?@MichaelWrighton
bar
foo
无关,为什么它应该在范围内?您要么必须导入foo.\uu
,要么必须引入某种带有参数列表的函数,该函数需要一个
foo
。否则,,