Scala 3中如何为元组定义可用于上下文参数的ValueOf?
实现支持元组的上下文参数版ValueOf
问题背景
ValueOf类型类可以在方法的上下文参数中获取单例类型的唯一实例,非单例类型会被编译器直接拒绝:
enum Color { case red, green, blue } def singleInhabitantOf[T](using holder: ValueOf[T]): T = holder.value println(singleInhabitantOf[Color.red.type] == Color.red) // 输出 true
但它存在局限——无法处理所有元素均为单例类型的元组,比如以下代码会编译失败:
singleInhabitantsOf[(Color.red.type, Color.blue.type)] // 编译错误
错误信息:No singleton value available for (Color.red, Color.blue); eligible singleton types for ValueOf synthesis include literals and stable paths.
尝试自定义ValuesOf类型别名适配元组,但编译器无法自动合成对应的上下文实例:
import scala.Tuple type ValuesOf[T <: Tuple] <: Tuple = T match { case EmptyTuple => EmptyTuple case h *: t => ValueOf[h] *: ValuesOf[t] } def singleInhabitantsOf[T <: Tuple](using holder: ValuesOf[T]): Tuple = holder singleInhabitantsOf[(Color.red.type, Color.blue.type)] // 编译错误:找不到ValuesOf类型的given实例
虽然summonAll[ValuesOf[(Color.red.type, Color.blue.type)]]可以正常运行,但用它实现的方法无法在签名阶段完成单例性检查,不符合需求。
解决方案
我们需要定义一个递归的类型类,并为元组的不同情况提供自动合成的given实例,这样就能在上下文参数中完成类型检查:
import scala.Tuple // 定义支持元组的类型类 trait TupleValueOf[T <: Tuple] { def value: Tuple } object TupleValueOf { // 为空元组提供实例 given emptyTupleValueOf: TupleValueOf[EmptyTuple] with { override def value: EmptyTuple = EmptyTuple } // 为非空元组递归合成实例:头部元素有ValueOf,尾部有TupleValueOf given nonEmptyTupleValueOf[H, T <: Tuple]( using headValue: ValueOf[H], tailValue: TupleValueOf[T] ): TupleValueOf[H *: T] with { override def value: Tuple = headValue.value *: tailValue.value } } // 使用该类型类的方法 def singleInhabitantsOf[T <: Tuple](using tv: TupleValueOf[T]): Tuple = tv.value
现在测试代码可以正常编译运行:
enum Color { case red, green, blue } println(singleInhabitantsOf[(Color.red.type, Color.blue.type)]) // 输出 (red,blue)
如果传入包含非单例类型的元组,编译器会直接报错,满足签名阶段检查的需求:
singleInhabitantsOf[(Color, Color.blue.type)] // 编译错误:无法找到ValueOf[Color]的given实例
内容的提问来源于stack exchange,提问作者Readren
相关产品推荐
相关产品推荐

