隧道隐式参数到按名称调用函数体



考虑以下代码片段:

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

最新更新