Scala ZIO环境建设

Scala ZIO环境建设,scala,zio,Scala,Zio,我开始尝试ZIO,并尝试运行以下高度复杂的程序: import logger.{Logger, _} import zio.console._ import zio.{system, _} object MyApp extends App { override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = { app .provideSome[Logger](_ => Slf4jLogger.cr

我开始尝试ZIO,并尝试运行以下高度复杂的程序:

import logger.{Logger, _}
import zio.console._
import zio.{system, _}

object MyApp extends App {

  override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {

    app
      .provideSome[Logger](_ => Slf4jLogger.create) //1 
      .fold(_ => 1, _ => 0)
  }

  val app: ZIO[Console with system.System with Logger, SecurityException, Unit] =
    for {
      _         <- info("This message from the logger") //2
      maybeUser <- system.env("USER")
      _         <- maybeUser match {
                      case Some(userName) => putStrLn(s"Hello ${userName}!")
                      case None => putStrLn("I don't know your name")
                    }
    } yield ()
}
我不明白以下几点:

  • 该程序需要一个
    控制台
    和环境中的
    系统
    实例,但我以前不需要
    。在我没有登录时,提供了它。为什么?为什么我突然需要它

  • 根据scaladoc,
    .provideSome
    提供了运行此效果所需的*部分*环境,其余部分为R0。对我来说,这意味着我不必提供完整的环境类型,我可以一个接一个地添加所需的模块——但它似乎期望使用完整的ZEnv类型,就像
    。provide
    ——那么这有什么意义呢

  • 我无法通过使用Console.Live with system.system.Live新建记录器来实例化匿名类,因为Slf4jLogger在伴随对象中有一个工厂方法。我如何将这种工厂方法用于其他特性

  • 因为在Java中创建一个logger实例是有效的,所以
    是否提供了可以调用的正确函数

  • PS:我能以一种丑陋的方式让它工作:

        app
          .provideSome[ZEnv](_ =>
            new Console with Logger with system.System {
              override val console = Console.Live.console
              override val system = System.Live.system
              override val logger = Slf4jLogger.create.logger
            }
          ) //1
          .fold(_ => 1, _ => 0)
    
    这将编译并运行,但覆盖混合特性的内部成员似乎不正确

    它的工作方式与
    完全相同。提供

        app
          .provide(
            new Console with Logger with system.System {
              override val console = Console.Live.console
              override val system = System.Live.system
              override val logger = Slf4jLogger.create.logger
            }
          ) //1
          .fold(_ => 1, _ => 0)
    
    发生了什么事?让我试着解释一下

    如果你看一下ZEnv是什么,它是带有控制台的时钟和带有随机阻塞的系统的别名。因此,当您开始实现
    def run(args:List[String]):ZIO[ZEnv,Nothing,Int]
    ZIO已经为您提供了这些功能

    您的
    应用程序
    变量签名的返回类型为zio,带有环境
    控制台和带有记录器的系统
    ——突出的一点是
    记录器
    功能。这不是标准的,所以ZIO不能提供给你。你必须自己提供

    这就是您使用
    所做的。provideSome[Logger]
    -您从环境要求中删除了一项功能,使其类型与标准兼容:

    type ZEnv = Clock with Console with System with Random with Blocking
    type YourEnv = Console with System
    type Proof = ZEnv <:< YourEnv
    
    类型ZEnv=带控制台的时钟,带随机阻塞的系统
    键入YourEnv=带有系统的控制台
    
    type-Proof=ZEnv恐怕您必须返回一个实例,该实例实现了您想要提供的所有特性

    如果您查看ZIO文档中有关
    provideSome
    的示例,您会发现他们正在做完全相同的事情:他们使用
    控制台
    ,并将其转换为带有日志记录的
    控制台

    /**
       * Provides some of the environment required to run this effect,
       * leaving the remainder `R0`.
       *
       * {{{
       * val effect: ZIO[Console with Logging, Nothing, Unit] = ???
       *
       * effect.provideSome[Console](console =>
       *   new Console with Logging {
       *     val console = console
       *     val logging = new Logging {
       *       def log(line: String) = console.putStrLn(line)
       *     }
       *   }
       * )
       * }}}
       */
    
    .provideSome[ZEnv](_ =>
            new Console with Logger with system.System {
              override val console = Console.Live.console
    
    对我来说,这意味着我不必提供完整的环境类型,我可以逐个添加所需的模块

    不可以。您必须提供完整环境类型的实例,以达到您正在包装的效果(因为它需要)。我认为这是因为我们希望在编译时检查它,如果不详细说明如何生成“mashup”堆叠环境(没有宏),就无法生成。今后可能会有一些宏用于此

    就像。提供-那有什么意义呢

    不同之处在于,使用
    .provide
    ,您必须从头开始构建所需环境的实例,而无需任何输入。因此,效果(包装)不再需要任何东西

    而使用
    .provideSome
    您自己可以请求一个环境来帮助您构建所提供的实例。该环境将被传递到您的函数中。在上面的示例中,它们需要一个
    控制台
    ,并通过日志
    将其扩展到
    控制台(通过使用
    控制台
    实例)。因此,
    effect.provideSome[Console](…)
    仍然需要
    控制台
    (而使用
    编写。provide
    则不需要
    任何东西

    由于您使用的是
    provideSome[ZEnv]
    ,您可能不应该访问全局单例
    控制台.Live
    ,而是从传入的
    env
    获取它:

    .provideSome[ZEnv](env =>
            new Console with Logger with system.System {
              override val console = env.console
    
    该程序需要一个控制台和环境中的一个系统实例,但我以前不必提供它

    这是因为默认环境已经提供了这两种功能

    因为在Java中创建一个logger实例是非常有效的,所以是否提供了正确的函数来调用

    就我个人而言,我会忽略构建记录器是有效的。这似乎不值得追踪。我认为它是基本的工具,它几乎是类加载的一部分。

    如果您确实想跟踪效果,您可以这样做

    app
      .provideSomeM(env => for {
         logger <- UIO(Slf4jLogger.create)
       } yield new MyEnvironment(env, logger)
      )
    
    app
    .provideSomeM(环境=>用于{
    
    这是我使用的一种方法:

    import logger.{Logger, _}
    import zio.console._
    import zio.{system, _}
    
    object MyApp extends App {
    
      override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
    
        app
          .fold(_ => 1, _ => 0)
      }
    
      val app: ZIO[Environment, SecurityException, Unit] =
        for {
          _         <- info("This message from the logger").provide( Slf4jLogger.create) // 1
          maybeUser <- system.env("USER")
          _         <- maybeUser match {
                          case Some(userName) => putStrLn(s"Hello ${userName}!")
                          case None => putStrLn("I don't know your name")
                        }
        } yield ()
    }
    
    导入记录器。{logger,}
    导入zio.console_
    导入zio.{system,}
    对象MyApp扩展应用程序{
    覆盖def运行(args:List[String]):ZIO[ZEnv,Nothing,Int]={
    应用程序
    .fold(=>1,=>0)
    }
    val应用程序:ZIO[环境、安全例外、单位]=
    为了{
    
    _我的逻辑也是这样的。但是第一个代码没有编译。所以这个逻辑是错误的:)如果我注释掉原始代码中的行
    //1
    //2
    ,我仍然有编译错误
    错误:(11,12)类型不匹配;发现:zio.zio[zio.console.console with zio.system.system with nequi.zio.logger.logger,Nothing,Int]必需:zio.zio[zio.ZEnv,Nothing,Int](扩展为)zio.zio[zio.clock.clock with zio.console.console with zio.system.system with zio.random with zio.blocking.blocking,Nothing,Int]。折叠(=>1,=>0)
    有关帮助使用样板文件的宏,请参见
    import logger.{Logger, _}
    import zio.console._
    import zio.{system, _}
    
    object MyApp extends App {
    
      override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
    
        app
          .fold(_ => 1, _ => 0)
      }
    
      val app: ZIO[Environment, SecurityException, Unit] =
        for {
          _         <- info("This message from the logger").provide( Slf4jLogger.create) // 1
          maybeUser <- system.env("USER")
          _         <- maybeUser match {
                          case Some(userName) => putStrLn(s"Hello ${userName}!")
                          case None => putStrLn("I don't know your name")
                        }
        } yield ()
    }