我创建类并通过宏将它分配给对象的字段。 当我通过函数体定义类方法体时,编译器会给出错误。但是,如果我通过硬编码定义主体,它就可以工作。
这是示例程序
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 }
如何使用函数定义类方法?