You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 07:25:24