我在Scala 3中定义了以下特质:
trait A[T <: Tuple]
使用Scala 3的宏,我会创建实现进一步检查元组
T
实际类型的 trait 对象;特别地,我希望检查元组 T
所有类型 (T_1
, …, T_n
) 是否为另一个给定类型 B
的子类型:trait B
private def allSubtypesOfB[T <: Tuple: Type](using quotes: Quotes): Boolean = {
import quotes.reflect.*
case '[Nothing] => false // I don't want nothing to be in T
case '[head *: tail] if TypeRepr.of[head] <:< TypeRepr.of[B] => allSubtypesOfB[tail]
case '[EmptyTuple] => true
case _ => false
}
inline def createA[T <: Tuple] = ${ createAImpl[T] }
private def createAImpl[T <: Tuple: Type](using quotes: Quotes): Expr[A[T]] = {
import quotes.reflect.*
if !allSubtypesOfB[T] then report.error("All types in T must be subtypes of B")
// ... create instance of A
}
问题在于之后,我需要对元组类型
T
中的每个类型调用具有以下签名的方法:def doSomethingWithBSubtype[T <: B] = ??? // Do something with type T
因此,代码应该类似于这样:
private def createAImpl[T <: Tuple: Type](using quotes: Quotes): Expr[A[T]] = {
import quotes.reflect.*
if !allSubtypesOfB[T] then report.error("All types in T must be subtypes of B")
Type.of[T] match {
case '[head *: tail] => doSomethingWithBSubtype[head]
case '[EmptyTuple] => ???
}
// ... create instance of A
}
这段代码无法编译,因为编译器指出 head
必须是 B
的子类型,才能在方法 doSomethingWithBSubtype
中使用。然而,在 match
前面的 if
语句中,我已经确保了 T
内部的所有类型都是 B
的子类型。是否有一种方式可以强制编译器将 head
视为 B
的子类型呢?