使用宏获取 Scala Class 的已实现类型
Obtaining the realised type for a Scala Class using macros
我在使用 Scala 宏和识别构造函数的实现类型时遇到了一些问题。
不确定我是否在这里做错了什么或正确的电话是什么。
从文档来看,typeSignatureIn
应该 return 是正确的信息,例如ClassTag[Int],但是当我 运行 宏时,我实际上得到了无法编译的 ClassTag[U],因为 U 是类型参数,而不是实现的类型。
import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.Context
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val typeToMock = weakTypeOf[T]
val primaryConstructorOpt = typeToMock.members.collectFirst {
case method: MethodSymbolApi if method.isPrimaryConstructor => method
}
val constructorArgumentsTypes = primaryConstructorOpt.map {
constructor =>
val constructorTypeContext = constructor.typeSignatureIn(typeToMock)
val constructorArguments = constructor.paramss
constructorArguments.map { symbols =>
symbols.map(_.typeSignatureIn(constructorTypeContext))
}
}
println(typeToMock)
println(constructorArgumentsTypes)
c.literalUnit
}
def foo[T] = macro macroImpl[T]
class Foo[U: ClassTag]
foo[Foo[Int]]
运行宁其:
scala> foo[Foo[Int]]
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[U]))
我需要以某种方式获取 ClassTag[Int] 以便稍后能够生成正确的树,有什么想法吗?
尝试在解析类型的每个地方使用 dealias
。 Scala 保留引用,即使它知道它们引用的是什么。 dealias
获取已替换引用的类型的副本 (?)。
您还应该选择黑盒或白盒宏,而不仅仅是 scala.reflect.macros.Context
。
这似乎有效:
import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.whitebox.Context
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val typeToMock = weakTypeOf[T].dealias
val primaryConstructorOpt = typeToMock.members.collectFirst {
case method: MethodSymbolApi if method.isPrimaryConstructor => method
}
val constructorArgumentsTypes = primaryConstructorOpt.map { constructor =>
val constructorTypeContext = constructor.typeSignatureIn(typeToMock).dealias
val constructorArguments = constructorTypeContext.paramLists
constructorArguments.map { symbols =>
symbols.map(_.typeSignatureIn(constructorTypeContext).dealias)
}
}
println(typeToMock)
println(constructorArgumentsTypes)
q"()"
}
def foo[T]: Any = macro macroImpl[T]
class Foo[U: ClassTag]
foo[Foo[Int]]
结果
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[Int])))
我在使用 Scala 宏和识别构造函数的实现类型时遇到了一些问题。
不确定我是否在这里做错了什么或正确的电话是什么。
从文档来看,typeSignatureIn
应该 return 是正确的信息,例如ClassTag[Int],但是当我 运行 宏时,我实际上得到了无法编译的 ClassTag[U],因为 U 是类型参数,而不是实现的类型。
import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.Context
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val typeToMock = weakTypeOf[T]
val primaryConstructorOpt = typeToMock.members.collectFirst {
case method: MethodSymbolApi if method.isPrimaryConstructor => method
}
val constructorArgumentsTypes = primaryConstructorOpt.map {
constructor =>
val constructorTypeContext = constructor.typeSignatureIn(typeToMock)
val constructorArguments = constructor.paramss
constructorArguments.map { symbols =>
symbols.map(_.typeSignatureIn(constructorTypeContext))
}
}
println(typeToMock)
println(constructorArgumentsTypes)
c.literalUnit
}
def foo[T] = macro macroImpl[T]
class Foo[U: ClassTag]
foo[Foo[Int]]
运行宁其:
scala> foo[Foo[Int]]
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[U]))
我需要以某种方式获取 ClassTag[Int] 以便稍后能够生成正确的树,有什么想法吗?
尝试在解析类型的每个地方使用 dealias
。 Scala 保留引用,即使它知道它们引用的是什么。 dealias
获取已替换引用的类型的副本 (?)。
您还应该选择黑盒或白盒宏,而不仅仅是 scala.reflect.macros.Context
。
这似乎有效:
import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.whitebox.Context
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val typeToMock = weakTypeOf[T].dealias
val primaryConstructorOpt = typeToMock.members.collectFirst {
case method: MethodSymbolApi if method.isPrimaryConstructor => method
}
val constructorArgumentsTypes = primaryConstructorOpt.map { constructor =>
val constructorTypeContext = constructor.typeSignatureIn(typeToMock).dealias
val constructorArguments = constructorTypeContext.paramLists
constructorArguments.map { symbols =>
symbols.map(_.typeSignatureIn(constructorTypeContext).dealias)
}
}
println(typeToMock)
println(constructorArgumentsTypes)
q"()"
}
def foo[T]: Any = macro macroImpl[T]
class Foo[U: ClassTag]
foo[Foo[Int]]
结果
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[Int])))