Ausgabe
Ich lerne ZIO 2.x, bei der Konfiguration Runtime
mit bootstrap
Layer funktioniert es nicht.
object RuntimeCustom extends ZIOAppDefault {
// It's not work, And I don't know why?
override val bootstrap = EmailService.live
def run = (for {
_ <- ZIO.debug("Start...")
_ <- EmailService.send("God", "Hi")
_ <- ZIO.debug("End...")
} yield ())
}
Erhalten Sie einen Fehler:
[error] /Users/changzhi/github-repo/zio-start/src/main/scala/zio/reference/experiment/core/RuntimeCustom.scala:35:7:
[error]
[error] ──── ZIO APP ERROR ───────────────────────────────────────────────────
[error]
[error] Your effect requires a service that is not in the environment.
[error] Please provide a layer for the following type:
[error]
[error] 1. example.EmailService
[error]
[error] Call your effect's provide method with the layers you need.
[error] You can read more about layers and providing services here:
[error]
[error] https://zio.dev/next/datatypes/contextual/
[error]
[error] ──────────────────────────────────────────────────────────────────────
[error]
[error] _ <- EmailService.send("God", "Hi")
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
Wenn ich durch ersetze provide
, funktioniert es.
object RuntimeCustom extends ZIOAppDefault {
def run = (for {
_ <- ZIO.debug("Start...")
_ <- EmailService.send("God", "Hi")
_ <- ZIO.debug("End...")
} yield ())
// This can works, have no doubt
.provide(EmailService.live)
}
Das Vollversionsprogramm ist hier
package example
import zio._
trait EmailService {
def send(user: String, content: String): Task[Unit]
}
object EmailService {
def send(user: String, content: String): ZIO[EmailService, Throwable, Unit] =
ZIO.serviceWithZIO[EmailService](_.send(user, content))
val live: ZLayer[Any, Nothing, EmailService] =
ZLayer.fromZIO( ZIO.succeed(EmailServiceFake()) <* Console.printLine("Init EmailService") ).orDie
}
case class EmailServiceFake() extends EmailService {
override def send(user: String, content: String): Task[Unit] =
Console.printLine(s"sending email to $user")
}
object RuntimeCustom extends ZIOAppDefault {
// It's not work, And I don't know why?
//override val bootstrap = EmailService.live
def run = (for {
_ <- ZIO.debug("Start...")
_ <- EmailService.send("God", "Hi")
_ <- ZIO.debug("End...")
} yield ())
// This can works, have no doubt
.provide(EmailService.live)
}
Lösung
ZIOAppDefault
für Apps gedacht ist, die keine zusätzlichen Dienste benötigen, wird davon ausgegangen, dass sie nur die integrierten Dienste “benötigen”, da Sie Ihre anderen Anforderungen mit der Methode bereitgestellt haben.provide
Wenn Sie die Methode verwenden möchten, bootstrap
sollten Sie stattdessen die Felder und erweitern ZIOApp
und überschreiben , damit der Mechanismus weiß, wie die endgültige Umgebung zu erstellen ist.environmentTag
Environment
run
import zio._
object App extends ZIOApp {
// Tell ZIO how the environment is constructed
override val environmentTag: EnvironmentTag[Environment] = EnvironmentTag[Environment]
// Tell the app which layers will be leftover from the `run`
override type Environment = FooService
// The app how to construct those remaining layers
override val bootstrap = FooService.layer
val run = FooService.doFoo
}
class FooService {
def doFoo: UIO[Unit] = ZIO.unit
}
object FooService {
val layer = ZLayer.succeed(new FooService)
def doFoo = ZIO.serviceWithZIO[FooService](_.doFoo)
}
Bearbeiten
Um zu zeigen, dass dies funktioniert, verwenden Sie das ursprüngliche Beispiel:
import zio._
trait EmailService {
def send(user: String, content: String): Task[Unit]
}
object EmailService {
def send(user: String, content: String): ZIO[EmailService, Throwable, Unit] =
ZIO.serviceWithZIO[EmailService](_.send(user, content))
val live: ZLayer[Any, Nothing, EmailService] =
ZLayer.fromZIO( ZIO.succeed(EmailServiceFake()) <* Console.printLine("Init EmailService") ).orDie
}
case class EmailServiceFake() extends EmailService {
override def send(user: String, content: String): Task[Unit] =
Console.printLine(s"sending email to $user")
}
object RuntimeCustom extends ZIOApp {
// It's not work, And I don't know why?
override val bootstrap = EmailService.live
override type Environment = EmailService
override val environmentTag: EnvironmentTag[Environment] = EnvironmentTag[Environment]
def run = (for {
_ <- ZIO.debug("Start...")
_ <- EmailService.send("God", "Hi")
_ <- ZIO.debug("End...")
} yield ())
}
https://scastie.scala-lang.org/02MMaWS2S6Wwe55a24H7Sg
Beantwortet von – paulpdaniels
Antwort geprüft von – Terry (FixError Volunteer)