3

考虑以下代码片段:

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在这种情况下是否有可能将隐式隧道转换为函数?

4

2 回答 2

0

简单地说——不。implicit要求从代码中可以明显看出发生了什么。如果您希望将任何内容隐式传递给函数,则它必须具有参数,而您的函数implicit不是这种情况。f

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

于 2015-09-20T18:15:52.660 回答
0

我的问题更多是关于为什么隐式定义在 run 没有隧道到调用者的运行体

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

  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
      }"""
    }
    
于 2015-09-20T18:16:04.460 回答