Scala 3 宏中的显式类型转换

Nic*_*oli 6 generics scala tuples scala-macros scala-3

我在 Scala 3 中定义了以下特征:

\n
trait A[T <: Tuple]\n
Run Code Online (Sandbox Code Playgroud)\n

然后,我使用 Scala 3 宏创建具有此特征的对象,对元组的实际类型执行进一步检查T;特别是,我想检查元组的所有类型(T_1,\xe2\x80\xa6,T_nT是否是另一个给定类型的子类型B

\n
trait B\nprivate def allSubtypesOfB[T <: Tuple: Type](using quotes: Quotes): Boolean = {\n    import quotes.reflect.*\n    case '[Nothing] => false // I don't want nothing to be in T\n    case '[head *: tail] if TypeRepr.of[head] <:< TypeRepr.of[B] => allSubtypesOfB[tail]\n    case '[EmptyTuple] => true\n    case _ => false\n}\n\ninline def createA[T <: Tuple] = ${ createAImpl[T] }\nprivate def createAImpl[T <: Tuple: Type](using quotes: Quotes): Expr[A[T]] = {\n    import quotes.reflect.*\n    if !allSubtypesOfB[T] then report.error("All types in T must be subtypes of B")\n    // ... create instance of A\n}\n
Run Code Online (Sandbox Code Playgroud)\n

问题是,稍后我需要为元组 type 中的每种类型调用T具有以下签名的方法:

\n
def doSomethingWithBSubtype[T <: B] = ??? // Do something with type T\n
Run Code Online (Sandbox Code Playgroud)\n

所以,代码看起来像这样:

\n
private def createAImpl[T <: Tuple: Type](using quotes: Quotes): Expr[A[T]] = {\n    import quotes.reflect.*\n    if !allSubtypesOfB[T] then report.error("All types in T must be subtypes of B")\n    Type.of[T] match {\n        case '[head *: tail] => doSomethingWithBSubtype[head]\n        case '[EmptyTuple] => ???\n    }\n    // ... create instance of A\n}\n
Run Code Online (Sandbox Code Playgroud)\n

此代码不会编译,因为编译器表示它必须是要在方法中使用的head子类型。然而,通过前面的例子,我已经确保里面的所有类型都是 的子类型。有没有办法强制编译器识别为 的子类型?BdoSomethingWithBSubtypeifmatchTBheadB

\n

Dmy*_*tin 2

宏有编译时和运行时之分。主要代码有编译时和运行时(使用宏)。宏的运行时间就是主代码的编译时间。

createAImpl该行内部if !allSubtypesOfB[T]...确保 的所有类型在 的运行时T都是 的子类型。但是当你调用时,你需要知道它是编译时的子类型,所以你还没有来​​自运行时的信息()。BcreateAImpldoSomethingWithBSubtype[head]headBcreateAImplcreateAImplif !allSubtypesOfB[T]...

你可以做

case '[head *: tail] => doSomethingWithBSubtype[head & B]
Run Code Online (Sandbox Code Playgroud)

也许像下面这样的事情是可能的

Type.of[T] match {
  case '[head *: tail] =>
    '{foo[head]} match {
      case '{
        type h <: B
        foo[`h`]
      } => doSomethingWithBSubtype[h]
    }
  case '[EmptyTuple] => ???
}

// outside def createAImpl, otherwise "access to method foo from wrong staging level"
def foo[A] = ???
Run Code Online (Sandbox Code Playgroud)

https://docs.scala-lang.org/scala3/guides/macros/quotes.html#type-variables-in-quoted-patterns

在某些情况下,我们需要定义一个被多次引用或具有某种类型界限的模式变量。为了实现这一点,可以使用type t类型模式变量在模式开始处创建模式变量。

scala 3中的fuseMap宏

什么 Scala 3 语法可以匹配宏上下文中的类型及其类型参数?

获取Scala3宏中的类型信息

将内联可变参数转换为通用元组