首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >scala-3宏支持编译时全局变量吗?如何使用它们?

scala-3宏支持编译时全局变量吗?如何使用它们?
EN

Stack Overflow用户
提问于 2022-11-21 16:21:07
回答 1查看 34关注 0票数 1

用例需要在运行时比较两种类型参数的实际类型。用TypeTag可以很容易地做到这一点,但是在scala-3中它是不可取的。因此,我尝试使用TypeTest,但它要求存在一个类型的实例,而我没有这种实例。因此,我实现了TypeId,这是我自己版本的TypeTag。它的方式更加有限和简单。它只支持类型比较,并且只在TypeId的单个实例存在于每个涉及的类型时才能工作。

代码语言:javascript
复制
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的值易受争用条件的影响。

我想知道是否可以使用宏在编译时创建唯一的ids。我认为要做到这一点,我需要某种编译时全局变量来实现排序器。scala-3宏支持编译时、全局变量还是实现我的目标的替代方案?

编辑:在问完我的问题几分钟后,我想出了一个非常简单的方法来实现我的目标,方法是将标识符设置为带有类型扩展名称的字符串。这样的名称可以很容易地在宏中生成。但是,我不想知道scala-3宏是否支持编译时全局变量。

下面是实现我的目标的代码,它使用类型的名称而不是顺序整数。

代码语言:javascript
复制
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
}
代码语言:javascript
复制
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])
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-21 17:01:17

这将是一个非常糟糕的想法,因为增量编译-它很难准确地知道什么将被编译或何时编译。您可以很容易地获得在clean编译上工作的内容,但是在开发期间部分重新编译时会失败,因为并不是所有应该触发排序器的代码都会被触发。

(我不确定它是否可行,可能还有其他原因来避免,但这是避免宏中任何类型的命令式代码的一个普遍原因。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74521882

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档