繁体   English   中英

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

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

请考虑以下代码段:

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

目前没有编译以下消息:

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

我的问题是可以使隐式参数可用于按名称调用函数体吗?

编辑我尝试使用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)

}

调试宏我可以看到它被正确扩展为

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

不幸的是,它没有编译同样的错误,没有发现隐式。

挖掘问题我发现这里的讨论和jira问题https://issues.scala-lang.org/browse/SI-5774

所以问题是一样的:在这种情况下是否有可能将隐式隧道传入todo函数?

简单地说 - 不。 implicit要求从代码中可以明显看出发生了什么。 如果你想隐式地将任何东西传递给一个函数,它必须有implicit参数,而不是f函数的情况。

这是implicit的智慧的重要来源: http//docs.scala-lang.org/tutorials/FAQ/finding-implicits.html

我的问题更多的是关于为什么运行中的隐式定义没有通过隧道传入调用者的运行体

因为这根本不是词法范围的工作方式。 它不在定义主体的范围内。 你有两个很好的选择:

  1.  def run(f: Int => Unit) = f(1) run { implicit i => todo // can use i here } 
  2. 使run的宏。 这至少应该是一个近似值(改编自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