scala 为什么重写Bootstrap,而不是Run方法?

2ic8powd  于 2022-11-09  发布在  Scala
关注(0)|答案(2)|浏览(200)

我正在学习ZIO 2.x,当使用bootstrap层配置Runtime时,它不工作。

  1. object RuntimeCustom extends ZIOAppDefault {
  2. // It's not work, And I don't know why?
  3. override val bootstrap = EmailService.live
  4. def run = (for {
  5. _ <- ZIO.debug("Start...")
  6. _ <- EmailService.send("God", "Hi")
  7. _ <- ZIO.debug("End...")
  8. } yield ())
  9. }

出现一个错误:

  1. [error] /Users/changzhi/github-repo/zio-start/src/main/scala/zio/reference/experiment/core/RuntimeCustom.scala:35:7:
  2. [error]
  3. [error] ──── ZIO APP ERROR ───────────────────────────────────────────────────
  4. [error]
  5. [error] Your effect requires a service that is not in the environment.
  6. [error] Please provide a layer for the following type:
  7. [error]
  8. [error] 1. example.EmailService
  9. [error]
  10. [error] Call your effect's provide method with the layers you need.
  11. [error] You can read more about layers and providing services here:
  12. [error]
  13. [error] https://zio.dev/next/datatypes/contextual/
  14. [error]
  15. [error] ──────────────────────────────────────────────────────────────────────
  16. [error]
  17. [error] _ <- EmailService.send("God", "Hi")
  18. [error] ^
  19. [error] one error found
  20. [error] (Compile / compileIncremental) Compilation failed

如果我用provide替换,它可以工作。

  1. object RuntimeCustom extends ZIOAppDefault {
  2. def run = (for {
  3. _ <- ZIO.debug("Start...")
  4. _ <- EmailService.send("God", "Hi")
  5. _ <- ZIO.debug("End...")
  6. } yield ())
  7. // This can works, have no doubt
  8. .provide(EmailService.live)
  9. }

完整版程序在此

  1. package example
  2. import zio._
  3. trait EmailService {
  4. def send(user: String, content: String): Task[Unit]
  5. }
  6. object EmailService {
  7. def send(user: String, content: String): ZIO[EmailService, Throwable, Unit] =
  8. ZIO.serviceWithZIO[EmailService](_.send(user, content))
  9. val live: ZLayer[Any, Nothing, EmailService] =
  10. ZLayer.fromZIO( ZIO.succeed(EmailServiceFake()) <* Console.printLine("Init EmailService") ).orDie
  11. }
  12. case class EmailServiceFake() extends EmailService {
  13. override def send(user: String, content: String): Task[Unit] =
  14. Console.printLine(s"sending email to $user")
  15. }
  16. object RuntimeCustom extends ZIOAppDefault {
  17. // It's not work, And I don't know why?
  18. //override val bootstrap = EmailService.live
  19. def run = (for {
  20. _ <- ZIO.debug("Start...")
  21. _ <- EmailService.send("God", "Hi")
  22. _ <- ZIO.debug("End...")
  23. } yield ())
  24. // This can works, have no doubt
  25. .provide(EmailService.live)
  26. }
ohfgkhjo

ohfgkhjo1#

ZIOAppDefault是为不需要额外服务的应用程序设计的,假设它们将只“需要”内置服务,因为您已经用provide方法提供了其他要求。
如果要使用bootstrap方法,则应该扩展ZIOApp并覆盖environmentTagEnvironment字段,以便run机制知道如何构造最终环境。

  1. import zio._
  2. object App extends ZIOApp {
  3. // Tell ZIO how the environment is constructed
  4. override val environmentTag: EnvironmentTag[Environment] = EnvironmentTag[Environment]
  5. // Tell the app which layers will be leftover from the `run`
  6. override type Environment = FooService
  7. // The app how to construct those remaining layers
  8. override val bootstrap = FooService.layer
  9. val run = FooService.doFoo
  10. }
  11. class FooService {
  12. def doFoo: UIO[Unit] = ZIO.unit
  13. }
  14. object FooService {
  15. val layer = ZLayer.succeed(new FooService)
  16. def doFoo = ZIO.serviceWithZIO[FooService](_.doFoo)
  17. }

编辑

使用原始示例来说明这是可行的:

  1. import zio._
  2. trait EmailService {
  3. def send(user: String, content: String): Task[Unit]
  4. }
  5. object EmailService {
  6. def send(user: String, content: String): ZIO[EmailService, Throwable, Unit] =
  7. ZIO.serviceWithZIO[EmailService](_.send(user, content))
  8. val live: ZLayer[Any, Nothing, EmailService] =
  9. ZLayer.fromZIO( ZIO.succeed(EmailServiceFake()) <* Console.printLine("Init EmailService") ).orDie
  10. }
  11. case class EmailServiceFake() extends EmailService {
  12. override def send(user: String, content: String): Task[Unit] =
  13. Console.printLine(s"sending email to $user")
  14. }
  15. object RuntimeCustom extends ZIOApp {
  16. // It's not work, And I don't know why?
  17. override val bootstrap = EmailService.live
  18. override type Environment = EmailService
  19. override val environmentTag: EnvironmentTag[Environment] = EnvironmentTag[Environment]
  20. def run = (for {
  21. _ <- ZIO.debug("Start...")
  22. _ <- EmailService.send("God", "Hi")
  23. _ <- ZIO.debug("End...")
  24. } yield ())
  25. }

https://scastie.scala-lang.org/02MMaWS2S6Wwe55a24H7Sg

展开查看全部
liwlm1x9

liwlm1x92#

像这样的事情应该会奏效:

  1. object YourApp extends ZIOAppDefault {
  2. def run = {
  3. val app = for {
  4. _ <- ZIO.debug("Start...")
  5. _ <- EmailService.send("God", "Hi")
  6. _ <- ZIO.debug("End...")
  7. } yield ()
  8. app.provideLayer(bootstrap)
  9. }
  10. override val bootstrap = {
  11. // val confLayer = ZLayer(...getArgs...) construct Layer from getArgs
  12. // confLayer >>> EmailService.live
  13. EmailService.live
  14. }
  15. }
展开查看全部

相关问题