我开始尝试使用 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 ()
}
(Slf4jLogger 是https://github.com/NeQuissimus/zio-slf4j)
如果我注释行//1
并且//2
一切正常。但在上面的表格中,我得到一个类型不匹配的错误:
Error:(13, 45) type mismatch;
found : logger.Slf4jLogger
required: zio.console.Console with zio.system.System with logger.Logger
.provideSome[Logger](_ => Slf4jLogger.create)
我不明白以下内容:
该程序在环境中需要一个
Console
和一个System
实例,但.provide
在我没有记录时,我以前不需要它。为什么?为什么我突然需要它?根据 scaladoc,
.provideSome
提供运行此效果所需的*一些*环境,剩下的为 R0。对我来说,这意味着我不必提供完整的环境类型,我可以一个一个地添加所需的模块——但它似乎期望完整的 ZEnv 类型,就像.provide
——那么有什么意义呢?我无法通过 实例化匿名类
new Logger with Console.Live with system.System.Live
,因为 Slf4jLogger 在伴随对象中有一个工厂方法。如何将此工厂方法与其他特征一起使用?由于在 Java 中创建一个记录器实例是一种有效的方法,
.provide
甚至是正确的函数调用吗?
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)
这编译并运行,但覆盖混合特征的内部成员似乎不正确......
它的工作方式与以下内容完全相同.provide
:
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)
到底是怎么回事?