Scala宏通用类的通用字段不适用于类通用类型参数。

4

通用的 case class

case class GroupResult[T](
  group: String,
  reduction: Seq[T]
)

宏方法
 def foo[T] = macro fooImpl[T]

 def fooImpl[T: c.WeakTypeTag](c: Context) = {
    import c.universe._
    val tpe = weakTypeOf[T]
     tpe.declarations.collect {
      case m: MethodSymbol if m.isCaseAccessor => println(m.returnType)
    }
    c.literalUnit
  }

当我调用foo[GroupResult[Int]]时,输出结果为:
String
Seq[T]

T没有被应用?我该如何获取已应用的Seq[Int]

1个回答

9

您可以使用 typeSignatureIn 来获取给定 GroupResult[Int] 的方法的类型签名:

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

case class GroupResult[T](group: String, reduction: Seq[T])

def foo[T] = macro fooImpl[T]

def fooImpl[T: c.WeakTypeTag](c: Context) = {
  import c.universe._

  val tpe = weakTypeOf[T]

  tpe.declarations.collect {
    case m: MethodSymbol if m.isCaseAccessor => println(m.typeSignatureIn(tpe))
  }

  c.literalUnit
}

然后:

scala> foo[GroupResult[Int]]
=> String
=> Seq[Int]

我们已经接近目标,现在我们正在获取访问器的“类型”,而不是它们的返回类型。如果我们需要返回类型,可以使用NullaryMethodType提取器:

def foo[T] = macro fooImpl[T]

def fooImpl[T: c.WeakTypeTag](c: Context) = {
  import c.universe._

  val tpe = weakTypeOf[T]

  tpe.declarations.collect {
    case m: MethodSymbol if m.isCaseAccessor => m.typeSignatureIn(tpe) match {
      case NullaryMethodType(returnType) => println(returnType)
    }
  }

  c.literalUnit
}

然后:
scala> foo[GroupResult[Int]]
String
Seq[Int]

我们完成了。


1
你是怎么知道的?有没有一些全面的材料可以学习这些东西? - jilen
很遗憾,我们的文档还没有完善。在http://docs.scala-lang.org/overviews/上有反射和宏的官方概述,但它们还有些不足。有几篇博客文章涵盖了实现细节(例如http://imranrashid.com/posts/scala-reflection/或http://blog.echo.sh/post/65955606729/exploring-scala-macros-map-to-case-class-conversion等),但据我所知,没有全面的列表。您也可以查看我们最近的研讨会:https://github.com/scalamacros/macrology201。 - Eugene Burmako

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接