Scala ZIO环境建设
我开始尝试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
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 ()
}
我不明白以下几点:
控制台
和环境中的系统
实例,但我以前不需要。在我没有登录时,提供了它。为什么?为什么我突然需要它
.provideSome
提供了运行此效果所需的*部分*环境,其余部分为R0。对我来说,这意味着我不必提供完整的环境类型,我可以一个接一个地添加所需的模块——但它似乎期望使用完整的ZEnv类型,就像。provide
——那么这有什么意义呢是否提供了可以调用的正确函数
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 ()
}