测试时如何为ZIO提供自定义Header并解决Tag缺失报错问题
问题解答
思路正确性说明
你的方向完全正确,ZIO[R, E, A]要消除R部分的依赖,就是通过provide/provideSomeLayer系列方法传入对应依赖的ZLayer,最终把环境类型收敛到你现有runtime支持的ZEnv就可以调用unsafeRunToFuture了。
报错原因说明
你遇到的编译错误是ZIO的类型标签要求:ZIO的Layer机制依赖izumi.reflect.Tag来做运行时类型识别,所有要放到Has容器里的类型、以及ZIO的输出类型A都需要对应的Tag隐式值,你现在的泛型A没有加Tag上下文约束,所以编译报错。
正确代码实现
你之前的实现有冗余逻辑,不需要额外封装ZManaged,直接构造静态值的Layer即可,修正后的代码如下:
import zio._ import izumi.reflect.Tag import scala.concurrent.duration._ import com.twitter.util.Await object effectAwait { // 给泛型A加上Tag上下文约束,满足ZIO类型系统要求 implicit class ZioEffect[A: Tag](private val value: ZIO[Has[EnvironmentHeader], RequestFailure, A]) extends AnyVal { final def await(implicit runtime: Runtime[ZEnv] = Runtime.default): A = { // 直接构造携带静态EnvironmentHeader的Layer val testHeaderLayer: ULayer[Has[EnvironmentHeader]] = ZLayer.succeed(EnvironmentHeader("test")) // 注入Has[EnvironmentHeader]依赖,剩余ZEnv依赖由传入的runtime提供 val effectWithEnv: ZIO[ZEnv, RequestFailure, A] = value.provideSomeLayer[ZEnv](testHeaderLayer) // 转换为Future后等待执行完成 val twitterFuture = runtime.unsafeRunToFuture(effectWithEnv) Await.result(twitterFuture, 10.seconds) } } }
额外说明
- 如果你使用的是ZIO 2版本,
Has已经被内置到环境类型体系中,语法会更简洁,直接写ZLayer.succeed(EnvironmentHeader("test"))即可,不需要额外处理Has包装 - 如果你的
RequestFailure是自定义错误类型,也需要保证它有对应的Tag隐式值,否则也会报类似编译错误,给错误类型加上E: Tag的上下文约束即可解决
内容的提问来源于stack exchange,提问作者Anders Martini
相关产品推荐
相关产品推荐

