斯卡拉宏分配解构功能

问题描述:

我目前正在玩弄宏了一下,也许这是一个不好的想法,但这里的PARAM是我的问题:斯卡拉宏分配解构功能

我有以下宏:

def using[A <: { def close(): Unit }, B](resource: A)(f: A => B) = macro usingImpl[A, B] 

def usingImpl[A <: { def close(): Unit }, B](c: Context)(resource: c.Expr[A])(f: c.Expr[A => B]): c.Expr[B] = { 

    import c.universe._ 


    f.tree match { 
    case Function(params, body) => 
     //val ValDef(modifiers, name, tpt, _) = params.head 
     c.Expr[B](
     Block(
      List(
      //ValDef(modifiers, name, tpt, resource.tree) 
      ValDef(params.head.symbol, resource.tree) 
     ), 
      body 
     ) 
    ) 

    case _: Select => 
     reify { 
     val res = resource.splice 
     try { 
      f.splice(res) 
     } finally { 
      res.close() 
     } 
     } 
    } 
} 

Select的情况下,我只需调用该函数并关闭资源即可正常工作。但在Function的情况下,我想将参数值分配给资源并调用正文。当我使用ValDef的已弃用创建者时,需要SymbolTree,一切正常。如果我使用的是过时的4-args创建者,我收到一个编译器错误,指出值x$1不在范围内。当我在看代码,这两个版本的产品,它看起来完全一样:

Expr[Int]({ 
    <synthetic> val x$1: Test.Foo = new Test.this.Foo(); 
    x$1.bar.+(23) 
}) 

有可能的方式,简单地使用params.head并分配一个值?谢谢你的帮助!

编辑

我这样调用宏:

object Test extends App { 
    import Macros._ 

    class Foo { 
    def close() {} 

    def bar = 3 
    } 

    println(using(new Foo)(_.bar + 3)) 
} 

正如我所说的,如果我使用了注释的版本,它给了我一个编译器错误,即打印AST和最后这条消息:[error] symbol value x$1 does not exist in Test$delayedInit$body.apply

而且我正在使用2.10.1。

+1

解构'params.head'应该可以很好地工作 - 我不能重现你的错误(使用2.10.0或者2.10.1),并且实际上在未注释的版本中出现编译器错误。你可以发布你用来调用宏的代码吗? – 2013-05-08 23:42:19

+0

更新了我的问题 – drexin 2013-05-09 00:08:56

+0

您一直在试图使Scala中的析构函数?好想法! – 2014-01-21 00:36:58

啊,现在我可以重现你的错误。任何时候你得到“这个条目似乎已经杀死了编译器。”消息看行这样的堆栈跟踪:

at scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:49) 

你的下一步行动应该是开始于c.resetAllAttrs包裹的东西。说实话,我第一次无法重现错误的原因是因为我在复制和粘贴代码之后用c.resetAllAttrs(body)代替了body块,甚至没有考虑它。这只是一个反射。

例如参见this little single abstract method class demo查看需要使用此技巧的地点的类似实例。

在你的情况,如果我们有这样的:

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

object Macros { 
    def using[A <: { def close(): Unit }, B](resource: A)(f: A => B) = 
    macro usingImpl[A, B] 

    def usingImpl[A <: { def close(): Unit }, B](c: Context) 
    (resource: c.Expr[A])(f: c.Expr[A => B]): c.Expr[B] = { 
    import c.universe._ 

    val expr = f.tree match { 
     case Function(ValDef(modifiers, name, tpt, _) :: Nil, body) => 
     c.Expr[B](
      Block(
      ValDef(modifiers, name, tpt, resource.tree) :: Nil, 
      c.resetAllAttrs(body) 
     ) 
     ) 

     case _: Select => reify { 
     val res = resource.splice 
     try { f.splice(res) } finally { res.close() } 
     } 
    } 

    println(expr) 
    expr 
    } 
} 

我们将看到以下,当我们编写测试代码:

Expr[B]({ 
    <synthetic> val x$1: $line3.$read.$iw.$iw.Test.Foo = new Test.this.Foo(); 
    x$1.bar.$plus(3) 
}) 

正是根据需要。

+0

工程就像一个魅力,非常感谢你! – drexin 2013-05-09 07:38:41