Scala 3中ZLayer内标记类型无法编译的问题排查
Scala 3标记类型在ZIO中缺失Tag隐式的解决方案
你的问题出在自定义标记类型的定义上,导致ZIO依赖的izumi.reflect.Tag无法自动生成对应实例。原来的Tagged opaque类型底层是Any,使得String @@ Tag1和String @@ Tag2在类型信息层面无法被Tag机制区分,最终编译报错。
解决方法:调整标记类型定义
修改TaggedTypes,将Tagged的底层类型设为V而非Any,同时保留标记的类型参数,这样izumi-reflect就能正确推导Tag:
object TaggedTypes { opaque type Tagged[V, Tag] = V type @@[V, Tag] = Tagged[V, Tag] def tag[Tag]: [V] => V => V @@ Tag = [V] => (v: V) => v.asInstanceOf[V @@ Tag] }
完整可运行代码
object TaggedTypes { opaque type Tagged[V, Tag] = V type @@[V, Tag] = Tagged[V, Tag] def tag[Tag]: [V] => V => V @@ Tag = [V] => (v: V) => v.asInstanceOf[V @@ Tag] } import TaggedTypes.* import zio.{ULayer, UIO, ZIO, ZLayer} import zio.Console trait Tag1 trait Tag2 val layer1: ULayer[String @@ Tag1] = ZLayer.succeed(tag[Tag1]("string1")) val layer2: ULayer[String @@ Tag2] = ZLayer.succeed(tag[Tag2]("string2")) val program: UIO[Unit] = for { string1 <- ZIO.service[String @@ Tag1] string2 <- ZIO.service[String @@ Tag2] _ <- Console.printLine(s"This should have value 'string1': ${string1}") _ <- Console.printLine(s"This should have value 'string2': ${string2}") } yield () object Main extends zio.ZIOAppDefault { override def run = program.provide(layer1, layer2) }
原理说明
原来的Tagged[V, Tag] = Any会让V @@ Tag退化为V & Any(本质还是V),Tag机制无法区分不同标记的同类型值。调整后,Tagged[V, Tag]作为带标记参数的opaque类型,保留了完整的类型信息,izumi-reflect可以为其生成唯一的Tag实例,让ZIO的依赖注入系统能正确区分String @@ Tag1和String @@ Tag2。
内容的提问来源于stack exchange,提问作者Emilis Panovas
相关产品推荐
相关产品推荐

