Scala宏将函数转换为方法

时间:2016-06-28 17:06:44

标签: scala macros

我创建类并通过宏将它分配给对象的字段。 当我通过函数体定义类方法体时,编译器会给出错误。但是,如果我通过硬编码定义主体,它就可以工作。

这是示例程序

object Main {

    trait SAM{
        def sum(d:Int,e:Int):Int
    }

    class Simple{
        var s:SAM=null
        def sam(c:SAM) = s = c
        def run(a:Int,b:Int)= if (s!=null) s.sum(a,b) else 0
    }


    def main(args: Array[String]) {
        val simple=new Simple()
        simple.set("sam")((x:Int,y:Int) ⇒ x+y)
        println(simple.run(8,9))
    }
}

这是我的宏(参见val createClass)

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

object MacroTest {

    implicit class MacroTestExtensions[T <: AnyRef](bean: T) {
        def set(name: String)(arg: Any) = macro implMethod[T]
    }

    def implMethod[T: c.WeakTypeTag]
    (c: Context)
    (name: c.Expr[String])
    (arg: c.Expr[Any]): c.Expr[T] = {
        import c.universe._

        val q"$_[$_]($bean)" = c.typecheck(c.prefix.tree)

        val nameMember = name.tree match {
            case Literal(Constant(fieldName: String)) => fieldName
        }

        val beanMethod = bean.tpe.member(TermName(nameMember)).filter(s => s.isMethod && s.asMethod.paramLists.flatten.size == 1)

        val Seq(param) = beanMethod.asMethod.paramLists.flatten
        val beanMethodType = param.typeSignature

        val methodSAM=beanMethodType.members.filter(s ⇒ s.isMethod && s.isAbstract).head

        val q"(..$params) => $body" = arg.tree

        val createClass=
            q"""new $beanMethodType{
                def ${methodSAM.asTerm.name}(..$params) : ${body.tpe} = $body
             }"""
        //this error in place: = $body

        c.Expr[T](q"""$bean.$beanMethod($createClass )
                      $bean""")
    }
}

但是,如果我定义为

        val createClass=
            q"""new $beanMethodType{
                def ${methodSAM.asTerm.name}(..$params) : ${body.tpe} = x+y
             }"""

它正在运作。 (scala版本2.11.8) 和错误文本

Error:scalac: 
  symbol value x#27670 does not exist in com.simple.ex.Main.main, which contains locals value simple#17543,value args#17338. 
Method code: def main(args: scala.Array[scala.Predef.String]): scala.Unit = {
  val simple = new com#7.simple#8192.ex#8196.Main$Simple#9526();
  (({
    simple.sam({
      new <$anon: com#7.simple#8192.ex#8196.Main$SAM#9525>(x, y)
    });
    simple
  }): com#7.simple#8192.ex#8196.Main$Simple#9526);
  scala.Predef.println(scala.Int.box(simple.run(9, 10)))
}
     while compiling: \src\com\simple\ex\Main.scala
        during phase: icode
     library version: version 2.11.8
    compiler version: version 2.11.8
  reconstructed args: -language:experimental.macros -nobootcp -javabootclasspath ; -Yoverride-vars -Xexperimental -Yoverride-objects -uniqid -classpath ... -Yinfer-argument-types
  last tree to typer: Ident(y$1)
       tree position: line 24 of \src\com\simple\ex\Main.scala
            tree tpe: Int#1078
              symbol: value y$1#30691
   symbol definition: y$1#30691: Int#1078 (a TermSymbol)
      symbol package: com.simple.ex
       symbol owners: value y$1#30691 -> constructor Main$$anon$1#27684 -> <$anon: com#7.simple#8192.ex#8196.Main$SAM#9525>
           call site: <$anon: com#7.simple#8192.ex#8196.Main$SAM#9525> in package ex#8196 in package ex#8195
== Source file context for tree position ==
    21 
    22          val simple=new Simple()
    23          simple.set("sam")((x:Int,y:Int) => x*y)
    24          println(simple.run(9,10))
    25      }
    26  }

如何使用函数定义类方法?

0 个答案:

没有答案