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