Scala 3宏是否支持编译时全局变量?如何实现类型唯一标识?
运行时类型比较:Scala 3中替代TypeTag的TypeId实现与编译时全局变量疑问
我需要在运行时比较两个类型参数的实际类型。之前用TypeTag可以轻松实现,但Scala 3中TypeTag已被弃用;尝试使用TypeTest,却发现它要求对应类型存在实例,而我没有这类实例。因此我实现了简化版的TypeTag——TypeId,它仅支持类型比较,且要求每个涉及的类型仅存在一个TypeId实例。
初始实现代码
import scala.collection.{mutable, immutable} object TypeId { private var idSequencer: Int = 0 private val typeIds: mutable.HashMap[Int, TypeId[?]] = mutable.HashMap.empty private def registerNew[A](tm: TypeId[A]): Int = this.synchronized { idSequencer += 1 typeIds.put(idSequencer, tm) idSequencer } def knownTypeIds: immutable.HashMap[Int, TypeId[?]] = this.synchronized(immutable.HashMap.from(typeIds)) } trait TypeId[A] { val id: Int = registerNew(this) def equalsTo(that: TypeId[?]): Boolean = this.id == that.id }
这个实现需要通过同步机制保证线程安全,使用起来不太方便;而且knownTypeIds的值存在竞态条件风险。
我想知道是否可以通过宏在编译时生成唯一ID,这似乎需要编译时全局变量来实现序列生成器。Scala 3宏是否支持编译时全局变量?或者有其他替代方案能实现我的目标?
编辑:
提问后不久,我想到一种简单方案:将标识符设为类型的全名,该名称可通过宏轻松生成。但我仍保留原问题,想确认Scala 3宏是否支持编译时全局变量。
以下是使用类型名称而非序列整数实现目标的代码:
TypeId实现
import scala.collection.{immutable} object TypeId { @volatile private var typeIds: immutable.Set[String] = immutable.HashSet.empty def knownTypeIds: immutable.Set[String] = typeIds private inline def registerNew[A]: String = { val id = TypeIdMacros.createId[A] this.synchronized(typeIds += id) id } } trait TypeId[A] { val id: String = registerNew[A] def equalsTo(that: TypeId[?]): Boolean = this.id == that.id }
宏实现
import scala.quoted.{Quotes, Type, Expr} object TypeIdMacros { inline def createId[A]: String = ${createIdImpl[A]} def createIdImpl[A](using typeA: Type[A], quotes: Quotes): Expr[String] = Expr(Type.show[A]) }
内容的提问来源于stack exchange,提问作者Readren
相关产品推荐
相关产品推荐

