【发布时间】:2023-04-06 12:43:01
【问题描述】:
我有以下宏:
package macros
import scala.reflect.macros.blackbox.Context
object CompileTimeAssertions {
def mustBeCaseClass[T]: Unit =
macro CompileTimeAssertionsImpl.mustBeCaseClass[T]
}
object CompileTimeAssertionsImpl {
def mustBeCaseClass[T: c.WeakTypeTag](c: Context): c.Expr[Unit] = {
import c.universe._
val symbol = c.weakTypeTag[T].tpe.typeSymbol
if (!symbol.isClass || !symbol.asClass.isCaseClass) {
c.error(c.enclosingPosition, s"${symbol.fullName} must be a case class")
}
reify(Unit)
}
}
它在不涉及泛型时有效,但在涉及时失败:
import macros.CompileTimeAssertions._
import org.scalatest.{Matchers, WordSpec}
case class ACaseClass(foo: String, bar: String)
class NotACaseClass(baz: String)
class MacroSpec extends WordSpec with Matchers {
"the mustBeCaseClass macro" should {
"compile when passed a case class" in {
mustBeCaseClass[ACaseClass]
}
"not compile when passed a vanilla class" in {
// mustBeCaseClass[NotACaseClass] // fails to compile as expected.
}
"compile when working with generics" in {
// class CaseClassContainer[T] { mustBeCaseClass[T] } // fails to compile.
// new CaseClassContainer[ACaseClass]
}
}
}
编译器错误是我的:
MacroSpec.CaseClassContainer.T must be a case class
我想知道实例化 CaseClassContainer 时的 T 是什么。这甚至可能吗?如果可以,可以举个例子吗?
提前致谢。
【问题讨论】:
-
不幸的是,您尝试做的事情不可能以这种方式实现。 Def 宏在您编写它们时立即在该位置展开,因此在展开点您将看到的只是 T。
-
然而,如果你能改变你的方法来合并类型类,你可能会有所收获。即:你可以有一个
CaseClass[T]类型类,然后你就可以说class CaseClassContainer[T: CaseClass]。查看github.com/scalamacros/macrology201/tree/part2 了解如何编写此类宏。 -
谢谢尤金!请随时将这些复制并粘贴到答案中,我会将其标记为正确。否是一个答案,也许比我 13 分钟前的情况要好得多。
-
请注意,Twitter 的双射库提供了一个
IsCaseClass类型类,其中实例由a macro 生成。 -
我认为特拉维斯的评论应该是一个答案:)
标签: scala scala-macros scala-2.11