(我对Scala还是陌生的,希望这不是一个愚蠢的问题。)
据我所知,为函数implicit
声明参数具有两个(相关但完全不同)的用法:
当编译器可以找到唯一合适的值(在调用范围内)传递时,它使在调用给定函数时显式传递一个相应的参数 是可选的。
它使参数本身成为将传递给具有隐式参数的其他函数的合适值(当从给定函数中调用它们时)。
在代码中:
def someFunction(implicit someParameter: SomeClass) = { // Note `implicit`
...
// Note no argument supplied in following call;
// possible thanks to the combination of
// `implicit` in `someOtherFunction` (1) and
// `implicit` in line 1 above (2)
someOtherFunction
...
}
def someOtherFunction(implicit someOtherParameter: SomeClass) = {
...
}
implicit val someValue = new SomeClass(...)
// Note no argument supplied in following call;
// possible thanks to `implicit` (1)
someFunction
这似乎有些奇怪,不是吗?从第1行中删除implicit
会使两个调用(从其他位置调用someFunction
,从someOtherFunction
内部调用someFunction
)都无法编译。
这背后的原理是什么? (编辑:我的意思是官方的基本原理,以防在官方的Scala资源中找到任何内容。)
还有没有其他方法可以实现一个方法(即允许隐式地将参数传递给函数,而在调用其他函数时不允许在函数内隐式使用参数,和/或使用非隐式)调用其他函数时隐式参数)? (编辑:我稍微改变了这个问题。此外,为了澄清,我的意思是说是否存在一种允许这种语言的语言结构-不通过手动阴影或类似方法达到效果)
答案 0 :(得分:3)
第一个问题
这背后的原理是什么?
答案可能基于观点。
有没有其他方法可以达成目标?
是的,虽然要真正使用该参数,但比我最初想的要复杂一些:
def someFunction(implicit someParameter: SomeClass) = {
val _someParameter = someParameter // rename to make it accessible in the inner block
{
val someParameter = 0 // shadow someParameter by a non-implicit
someOtherFunction // doesn't compile
someOtherFunction(_someParameter) // passed explicitly
}
}
答案 1 :(得分:3)
理由很简单:
我认为任何其他组合(例如implicit
->显式,更不用说显式-> implicit
)都不会更容易理解。我认为,基本思想是可以建立一些通用的隐式上下文,然后定义一整套方法,这些方法期望使用描述所建立上下文的相同implicit
变量。
以下是从隐式到显式再返回的方法:
隐式->隐式(默认)
def foo(implicit x: Int): Unit = {
bar
}
def bar(implicit x: Int): Unit = {}
显式->隐式:
def foo(x: Int): Unit = {
implicit val implicitX = x
bar
}
def bar(implicit x: Int): Unit = {}
隐式->显式:我只会使用Alexey Romanov的解决方案,但是可以想象,如果我们在Predef
中使用以下方法:
def shadowing[A](f: Unit => A): A = f(())
然后我们可以这样写:
def foo(implicit x: Int): Unit = {
val explicitX = x
shadowing { x =>
// bar // doesn't compile
bar(explicitX) // ok
}
}
def bar(implicit x: Int): Unit = {}
从本质上讲,它与Alexey Romanov的解决方案相同:我们引入了一个隐藏隐式参数的虚拟变量,然后在仅该虚拟变量可见的范围内编写方法的主体。唯一的区别是在()
实现内部传递了一个shadowing
值,因此我们不必显式地分配一个0
。它并不会使代码短很多,但是也许表达的意图更加清晰。