我开始尝试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)
发生了什么事?
让我尝试解释。
恐怕您必须返回一个实例,该实例实现了您想提供的所有特征。