简体   繁体   English

Scala中隐式参数的两种不同用法?

[英]Two different uses of implicit parameters in Scala?

(I am fairly new to Scala, hope this isn't a stupid question.) (我对Scala相当新,希望这不是一个愚蠢的问题。)

From what I can see, declaring a parameter to a function implicit has two (related, but quite different) uses: 从我所看到的,将参数声明为implicit函数有两个 (相关但非常不同)的用途:

  1. It makes explicitly passing a corresponding argument when calling the given function optional when the compiler can find a unique suitable value to pass (in the calling scope). 当编译器可以找到要传递的唯一合适值(在调用范围内)时,它会在调用给定函数时显式传递相应的参数。

  2. It makes the parameter itself a suitable value to pass to other functions with implicit parameters (when calling them from within the given function). 它使参数本身成为一个合适的值,用于传递具有隐式参数的其他函数 (当从给定函数中调用它们时)。

In code: 在代码中:

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

This seems somewhat strange, doesn't it? 这看起来有些奇怪,不是吗? Removing implicit from line 1 would make both calls (to someFunction from some other place, and to someOtherFunction from within someFunction ) not compile. 从第1行中删除implicit将使得两个调用(来自someFunctionsomeFunction someOtherFunction )都不能编译。

What is the rationale behind this? 这背后的理由是什么? ( Edit: I mean what is the official rationale, in case any can be found in some official Scala resource.) 编辑:我的意思是官方的理由是什么,以防任何官方Scala资源中都可以找到。)

And is there a way to achieve one without the other (that is to allow passing an argument to a function implicitly without allowing it to be used implicitly within that function when calling other functions, and/or to use a non-implicit parameter implicitly when calling other functions)? 是否有一种方法可以实现一个没有另一个(即允许隐式地将参数传递给函数而不允许在调用其他函数时隐式地在该函数中使用它,和/或在隐式地使用非隐式参数时调用其他功能)? ( Edit: I changed the question a bit. Also, to clarify, I mean whether there is a language construct to allow this - not achieving the effect by manual shadowing or similar.) 编辑:我稍微改变了一下这个问题。另外,澄清一下,我的意思是说是否有一种语言结构允许这样做 - 没有通过手动阴影或类似方法实现效果。)

For the first question 对于第一个问题

What is the rationale behind this? 这背后的理由是什么?

answers are likely to be opinion-based. 答案很可能是基于意见的。

And is there a way to achieve one without the other? 有没有办法实现一个没有另一个?

Yes, though it's a bit trickier than I thought initially if you want to actually use the parameter: 是的,虽然如果你想要实际使用参数,它比我最初想象的要复杂一点:

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
  }
}

The rationale is simple: 理由很简单:

  • What has been passed as explicit, stays explicit 已明确传递的内容保持明确
  • What has been marked as implicit, stays implicit 被标记为隐含的内容,保持隐含

I don't think that any other combination (eg implicit -> explicit, let alone explicit -> implicit ) would be easier to understand. 我不认为任何其他组合(例如, implicit - >显式,更不用说显式 - > implicit )将更容易理解。 The basic idea was, I think, that one can establish some common implicit context, and then define whole bunch of methods that expect same implicit variables that describe the established context. 我认为,基本思想是,可以建立一些共同的隐式上下文,然后定义整个方法,这些方法期望描述已建立上下文的相同implicit变量。

Here is how you can go from implicit to explicit and back: 以下是从隐式到显式和返回的方法:

  • Implicit -> implicit (default) 隐式 - >隐式(默认)

     def foo(implicit x: Int): Unit = { bar } def bar(implicit x: Int): Unit = {} 
  • Explicit -> implicit: 显式 - >隐式:

     def foo(x: Int): Unit = { implicit val implicitX = x bar } def bar(implicit x: Int): Unit = {} 
  • Implicit -> explicit: I would just use Alexey Romanov's solution, but one could imagine that if we had the following method in Predef : 隐式 - >显式:我只会使用Alexey Romanov的解决方案,但可以想象如果我们在Predef使用以下方法:

     def shadowing[A](f: Unit => A): A = f(()) 

    then we could write something like this: 然后我们可以这样写:

     def foo(implicit x: Int): Unit = { val explicitX = x shadowing { x => // bar // doesn't compile bar(explicitX) // ok } } def bar(implicit x: Int): Unit = {} 

    Essentially, it's the same as Alexey Romanov's solution: we introduce a dummy variable that shadows the implicit argument, and then write the body of the method in the scope where only the dummy variable is visible. 本质上,它与Alexey Romanov的解决方案相同:我们引入一个隐藏隐式参数的虚拟变量,然后在只有虚拟变量可见的范围内编写方法体。 The only difference is that a () -value is passed inside the shadowing implementation, so we don't have to assign a 0 explicitly. 唯一的区别是a ()值在shadowing实现中传递,因此我们不必显式指定0 It doesn't make the code much shorter, but maybe it expresses the intent a little bit clearer. 它不会使代码更短,但也许它表达了更清晰的意图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM