scala 是否可以在ZIO效果中替换特定层并保留环境的其余部分?

zrfyljdw  于 6个月前  发布在  Scala
关注(0)|答案(1)|浏览(72)

ChatGPT说这应该可以工作,但看起来它是错误的:/

trait Foo { def s: String }
      case object A extends Foo { def s = "A" }
      case object B extends Foo { def s = "B" }
      test("Replace a service in ZIO") {
        val layer = ZLayer.succeed[Foo](A)
        val otherLayer = ZLayer.succeed[Foo](B)
        val app = (for {
          foo <- ZIO.service[Foo]
          bar <- ZIO.service[String]
        } yield foo.s + bar).provide(layer, ZLayer.succeed("foo"))

        val otherApp = app.provideSomeLayer(otherLayer)
        otherApp.map { s => assertTrue(s == "Bfoo") }
      }

字符串
这里有一个app,它有服务A和字符串“foo”。尝试从它创建otherApp,将A替换为B,并保持其余的(“foo”)不变。但是运气不好-这个测试失败了,因为结果值仍然是“Afoo”而不是“Bfoo”。
我做错了什么?
另外(在一个不同的主题上),如果我把provide改为provideLayer(layer).provide(ZLayer.succeed("foo"),它不再编译说它希望layer成为Foo with String
还有一个菜鸟问题,当我引起你的注意的时候。在什么时候这些ZIO实际上 * 运行 *?这个测试运行他们两个吗?或者它只运行otherApp,因为它是唯一一个用来产生返回值的?

9w11ddsr

9w11ddsr1#

尝试从它创建otherApp,用B替换A,并保持其余部分("foo")不变。
我不认为你可以“替换”一个层,一旦它被提供。
实际上,我甚至很惊讶你使用provideSomeLayer没有引发错误,因为你提供了太多的层。通常当提供了不必要的层时,它会编译失败。
有没有办法提供一些依赖关系的效果,并留下其他未定义的?
provideSome可以做到这一点:

val program: ZIO[Foo with String, Nothing, String] = (for {
  foo <- ZIO.service[Foo]
  bar <- ZIO.service[String]
} yield foo.s + bar)

// Providing only the String type, and leaving Foo to be defined later
val appPartial: ZIO[Foo, Nothing, String] = program.provideSome[Foo](ZLayer.succeed("foo"))

// Defining Foo now with B
val otherApp: ZIO[Any, Nothing, String] = appPartial.provide(otherLayer)

字符串
这些ZIO实际上是在什么时候运行的?
如果你在ZIO测试之外,那么在你给予ZIO"runtime"之前,什么都不会运行,就像这样:

Unsafe.unsafe { implicit unsafe =>
  zio.Runtime.default.unsafe.run(otherApp).getOrThrowFiberFailure()
}

但是在ZIO测试上下文中,框架为你运行效果。所以你不需要这个“运行时”的东西。我假设它只运行返回值的效果。

相关问题