简体   繁体   English

隧道隐式参数以call-by-name函数体

[英]Tunnel implicit parameter to call-by-name function body

Consider following code snippet: 请考虑以下代码段:

object Example {

    def run(f: => Unit): Unit = {
        implicit val i = 1

        f
    }

    def caller(): Unit =
        run {
            todo
        }

    def todo(implicit i: Int): Unit =
        println(i)
} 

which currently is not compiling with following message: 目前没有编译以下消息:

Error:(14, 13) could not find implicit value for parameter i: Int
            todo
        ^ 

My question is it possible to make implicit parameter available to call-by-name function body? 我的问题是可以使隐式参数可用于按名称调用函数体吗?

EDIT I tried make it working with macro implementation as suggested by Alexey Romanov 编辑我尝试使用Alexey Romanov建议的宏实现

import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

object Macros {

  def run(f: => Unit): Unit = macro runImpl

  def runImpl(c : Context)(f: c.Tree) = {
      import c.universe._
      q"""{
        implicit val i: Int = 3
        $f
      }"""
  }
}

object Example extends App {

    Macros.run {
       todo
    }

    def todo(implicit i: Int): Unit =
       println(i)

}

Debugging macro i can see that it is correctly expanded into 调试宏我可以看到它被正确扩展为

{
   implicit val i: Int = 3
   Example.this.todo
}

Unfortunately it does not compiles as well with same error that implicit is not found. 不幸的是,它没有编译同样的错误,没有发现隐式。

Digging into issue i found discussions here and jira issues https://issues.scala-lang.org/browse/SI-5774 挖掘问题我发现这里的讨论和jira问题https://issues.scala-lang.org/browse/SI-5774

So question is the same: Is it possible to tunnel implicit into todo function in this case? 所以问题是一样的:在这种情况下是否有可能将隐式隧道传入todo函数?

Simply said - no. 简单地说 - 不。 implicit requires that it is obvious from the code what is going on. implicit要求从代码中可以明显看出发生了什么。 If you want anything to be passed to a function implicitly, it must have implicit parameter which is not the case of your f function. 如果你想隐式地将任何东西传递给一个函数,它必须有implicit参数,而不是f函数的情况。

This is a great source of wisdom related to implicit : http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html 这是implicit的智慧的重要来源: http//docs.scala-lang.org/tutorials/FAQ/finding-implicits.html

My question was more about why implicit defined in run is not tunneled into caller's run body 我的问题更多的是关于为什么运行中的隐式定义没有通过隧道传入调用者的运行体

Because that's simply not how lexical scoping works. 因为这根本不是词法范围的工作方式。 It isn't in scope where the body is defined. 它不在定义主体的范围内。 You have two good alternatives: 你有两个很好的选择:

  1.  def run(f: Int => Unit) = f(1) run { implicit i => todo // can use i here } 
  2. Make run a macro. 使run的宏。 This should be at least an approximation (adapted from SI-5778 ), unfortunately I can't test it at the moment: 这至少应该是一个近似值(改编自SI-5778 ),遗憾的是我现在无法测试它:

     object Macros { def run(f: => Unit) = macro runImpl def runImpl(c : Context)(f: c.Tree) = q"""{ implicit val i: Int = 1 // some other implicits $f }""" } 

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

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