ZLayer[A, E, B] 描述应用程序的一层:应用程序中的每个层都需要一些服务(作为输入)并产生出一些服务(作为输出)。Layers 可以被视基于给定他们的依赖关系(其他服务)而产生这些服务绑定所需要的清单。
层的构造可以使资源的使用效果化,并且使资源被安全地获取,使用完后安全地释放。
默认情况下,层(Layer)是共享的,这意味着如果同一图层使用两次,则该图层将仅分配一次。由于层具有出色的可组合性,因此它们是 ZIO 中创建依赖于其他服务的服务的惯用方式。
最简单的 ZLayer 应用
import zio._
object Example extends zio.App {
  def run(args: List[String]): URIO[ZEnv, ExitCode] =
    zio.provideLayer(nameLayer).as(ExitCode.success)
  val zio = for {
    name <- ZIO.access[Has[String]](_.get)
    _    <- UIO(println(s"Hello, $name!"))
  } yield ()
  val nameLayer = ZLayer.succeed("Adam")}
具有依赖项的 ZLayer 应用
import zio._
import zio.console._
import zio.clock._
import java.io.IOException
import zio.duration.Duration._
object moduleA {
  type ModuleA = Has[ModuleA.Service]
  object ModuleA {
    trait Service {
      def letsGoA(v: Int): UIO[String]
    }
    val any: ZLayer[ModuleA, Nothing, ModuleA] =
      ZLayer.requires[ModuleA]
    val live: Layer[Nothing, Has[Service]] = ZLayer.succeed {
      new Service {
        def letsGoA(v: Int): UIO[String] = UIO(s"done: v = $v ")
      }
    }
  }
  def letsGoA(v: Int): URIO[ModuleA, String] =
    ZIO.accessM(_.get.letsGoA(v))
}
import moduleA._
object moduleB {
  type ModuleB = Has[ModuleB.Service]
  object ModuleB {
    trait Service {
      def letsGoB(v: Int): UIO[String]
    }
    val any: ZLayer[ModuleB, Nothing, ModuleB] =
      ZLayer.requires[ModuleB]
    val live: ZLayer[ModuleA, Nothing, ModuleB] = ZLayer.fromService { (moduleA: ModuleA.Service) =>
      new Service {
        def letsGoB(v: Int): UIO[String] =
          moduleA.letsGoA(v)
      }
    }
  }
  def letsGoB(v: Int): URIO[ModuleB, String] =
    ZIO.accessM(_.get.letsGoB(v))
}
object ZLayerApp0 extends zio.App {
  import moduleB._
  val env = Console.live ++ Clock.live ++ (ModuleA.live >>> ModuleB.live)
  val program: ZIO[Console with Clock with moduleB.ModuleB, IOException, Unit] =
    for {
      _ <- putStrLn(s"Welcome to ZIO!")
      _ <- sleep(Finite(1000))
      r <- letsGoB(10)
      _ <- putStrLn(r)
    } yield ()
  def run(args: List[String]) =
    program.provideLayer(env).exitCode
}
// output: 
// [info] running ZLayersApp 
// Welcome to ZIO!
// done: v = 10 
复杂的 ZLayer 依赖案例
import zio._
import zio.clock._
object ZLayerApp1 extends scala.App {
  val rt = Runtime.default
  type ModuleA = Has[ModuleA.Service]
  object ModuleA {
    trait Service {}
    val any: ZLayer[ModuleA, Nothing, ModuleA] =
      ZLayer.requires[ModuleA]
    val live: ZLayer[Any, Nothing, ModuleA] =
      ZLayer.succeed(new Service {})
  }
  type ModuleB = Has[ModuleB.Service]
  object ModuleB {
    trait Service {}
    val any: ZLayer[ModuleB, Nothing, ModuleB] =
      ZLayer.requires[ModuleB]
    val live: ZLayer[Any, Nothing, ModuleB] =
      ZLayer.succeed(new Service {})
  }
  type ModuleC = Has[ModuleC.Service]
  object ModuleC {
    trait Service {
      def foo: UIO[Int]
    }
    val any: ZLayer[ModuleC, Nothing, ModuleC] =
      ZLayer.requires[ModuleC]
    val live: ZLayer[ModuleA with ModuleB with Clock, Nothing, ModuleC] =
      ZLayer.succeed {
        new Service {
          val foo: UIO[Int] = UIO.succeed(42)
        }
      }
    val foo: URIO[ModuleC, Int] =
      ZIO.accessM(_.get.foo)
  }
  val env = (ModuleA.live ++ ModuleB.live ++ ZLayer.identity[Clock]) >>> ModuleC.live
  val res = ModuleC.foo.provideCustomLayer(env)
  val out = rt.unsafeRun(res)
  println(out)
  // 42
}