scala - 获取模块符号,假设我有模块类,scala 宏
问题描述
我正在尝试IsEnum[T]
使用宏构建一个简单的类型类。
我knownDirectSubclasses
用来获取所有直接子类 if T
, ensureT
是一个密封的特征,并且所有子类都是 case 对象(使用subSymbol.asClass.isModuleClass && subSymbol.asClass.isCaseClass
)。
现在我正在尝试Seq
使用子类引用的案例对象构建一个。
它正在工作,使用一种解决方法:
Ident(subSymbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol].sourceModule.asInstanceOf[Symbol])
但是我从其他一些问题中复制了它,但它看起来很笨拙和错误。为什么这行得通?有没有更清洁的方法来实现这一目标?
解决方案
在 2.13 中,您可以实现scala.ValueOf
val instanceTree = c.inferImplicitValue(appliedType(typeOf[ValueOf[_]].typeConstructor, subSymbol.asClass.toType))
q"$instanceTree.value"
树会不一样
sealed trait A
object A {
case object B extends A
case object C extends A
}
//scalac: Seq(new scala.ValueOf(A.this.B).value, new scala.ValueOf(A.this.C).value)
但在运行时它仍然是Seq(B, C)
.
在 2.12shapeless.Witness
中可以使用代替ValueOf
val instanceTree = c.inferImplicitValue(appliedType(typeOf[Witness.Aux[_]].typeConstructor, subSymbol.asClass.toType))
q"$instanceTree.value"
//scalac: Seq(Witness.mkWitness[App.A.B.type](A.this.B.asInstanceOf[App.A.B.type]).value, Witness.mkWitness[App.A.C.type](A.this.C.asInstanceOf[App.A.C.type]).value)
libraryDependencies += "com.chuusai" %% "shapeless" % "2.4.0-M1" // in 2.3.3 it doesn't work
在Shapeless中,他们使用了一种
subSymbol.asClass.toType match {
case ref @ TypeRef(_, sym, _) if sym.isModuleClass => mkAttributedQualifier(ref)
}
或者在我们的例子中
mkAttributedQualifier(subSymbol.asClass.toType)
但他们mkAttributedQualifier
也对编译器内部使用向下转换,获得的树就像Seq(A.this.B, A.this.C)
.
还
Ident(subSymbol.companionSymbol)
似乎工作(树是Seq(B, C)
)但.companionSymbol
已被弃用(在 scaladocs 中它写成“可能会返回模块类的意外结果”,即对象)。
遵循类似于@MateuszKubuszok在他的库enumz中使用的方法,您也可以尝试
val objectName = symbol.fullName
c.typecheck(c.parse(s"$objectName"))
树是Seq(App.A.B, App.A.C)
。
最后,如果您对树Seq(B, C)
(而不是更复杂的树)感兴趣,您似乎可以替换
Ident(subSymbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol].sourceModule.asInstanceOf[Symbol])
与更传统的
Ident(subSymbol.owner.info.decl(subSymbol.name.toTermName))
推荐阅读
- dll-injection - 为什么EasyHook的RhInjectLibrary函数在创建进程后会导致目标进程崩溃
- sql - 如果条件被证明为真,则创建列
- gramex - 当我创建一个 MLHandler 组件时,单击“/predict”链接 - 错误 502
- .net - 需要图像时,iframe 会进行 2 次调用
- java - SimpleDateFormat("EEEE") 为时区返回错误的星期几
- javascript - 渲染复杂 3D 模型 .obj - p5.js 的问题
- objective-c - Objective-C,Typhoon,KVO 的 keypath
- node.js - 尝试通过 Next.js API 路由上的 admin.firestore.v1.FirestoreAdminClient 导出备份。错误:无法加载默认凭据
- recharts - 删除 Recharts SimpleAreaChart 中的顶行
- c# - 根据属性值更改样式