在http4s版本19.0.0中找不到ContextShift [cats.effect.IO]的隐式值

时间:2019-01-07 01:57:35

标签: scala scala-cats http4s cats-effect

我有一个http4s项目,该项目使用ciris进行配置管理。

该项目位于github here中。

libraryDependencies ++= Seq(
  "is.cir" %% "ciris-cats",
  "is.cir" %% "ciris-cats-effect",
  "is.cir" %% "ciris-core",
  "is.cir" %% "ciris-enumeratum",
  "is.cir" %% "ciris-refined"
).map(_ % "0.12.1")

libraryDependencies ++= Seq(
  "org.http4s" %% "http4s-dsl",
  "org.http4s" %% "http4s-blaze-server"
).map(_ % "0.18.18")

libraryDependencies ++= Seq(
  "com.ovoenergy" %% "ciris-kubernetes" % "0.5",
  "org.typelevel" %% "kittens" % "1.2.0",
  "eu.timepit" %% "refined-cats" % "0.9.3"
)

编译项目时,出现错误here

    [info] Compiling 12 Scala sources to /Users/rajkumar.natarajan/Documents/Coding/OS/ciris-example/target/scala-2.12/classes ...
    [error] /Users/rajkumar.natarajan/Documents/Coding/OS/ciris-example/src/main/scala/is/cir/example/application/Http4sApi.scala:24:68: Cannot find an implicit value for ContextShift[cats.effect.IO]:
    [error] * import ContextShift[cats.effect.IO] from your effects library
    [error] * if using IO, use cats.effect.IOApp or build one with cats.effect.IO.contextShift
    [error]   implicit val ioConcurrentEffect: Concurrent[IO] = cats.effect.IO.ioConcurrentEffect
    [error]                                                                    ^
    [error] /Users/rajkumar.natarajan/Documents/Coding/OS/ciris-example/src/main/scala/is/cir/example/application/Http4sApi.scala:43:69: type mismatch;
    [error]  found   : (ec: scala.concurrent.ExecutionContext, sc: java.util.concurrent.ScheduledExecutorService)cats.effect.Timer[cats.effect.IO] <and> (ec: scala.concurrent.ExecutionContext)cats.effect.Timer[cats.effect.IO]
    [error]  required: cats.effect.Timer[cats.effect.IO]
    [error]         Timeout(finite)(service)(ioConcurrentEffect, cats.effect.IO.timer)
    [error]                                                                     ^

原因是我缺少函数here需要的隐式参数 该错误告诉我使用use cats.effect.IOApp or build one with cats.effect.IO.contextShift,但找不到cats.effect.IOAppcats.effect.IO.contextShift

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

我怀疑您不了解Scala中如何使用implicit。有several popular usages,其中之一是使用隐式传递一些“上下文”信息。您看到的代码就是这种用法的经典示例。

当您执行“超时”时,您需要决定两件事:

  • 主要作业将在哪里(哪个线程)上运行
  • 在JVM世界中(例如,与JavaScript不同),将在何处(在哪个线程上)启动计时器。

关于这些参数的重要一点是,一方面,它们对于工作是必不可少的,但另一方面,它们仅支持主要参数。另一件事是您可能只想拥有一个(或很少)全局对象,这些对象在各处都用于这些对象。这就是使它们成为上下文的原因,这就是为什么它们被隐式传递。

现在,您可以选择在何处获取它们:

  • 也将它们设为您的上下文,即,强制调用者将它们传递给您(同样是隐含的
  • 创建自己的实例

这个选择不是一个简单的设计决定,取决于您将如何使用您的API。通常,正确的选择是第一个-使它们成为您的上下文。这样,您就可以允许调用方以所需的方式设置上下文(例如,TimerConcurrent应该使用相同的线程池还是使用不同的线程池?)。有时可以创建自己的独立上下文。或者将您从外部收到的其他上下文包装到您特定的内容中。

假设您想将外部上下文包装在Http4sApi的边界处,则可以编写如下代码:

final case class Http4sApi()(implicit executionContext: ExecutionContext) extends HttpApiAlg[IO] {
  // create IO-specific context from the executionContext
  private implicit val cs = IO.contextShift(executionContext)
  private implicit val timer = IO.timer(executionContext)

那你就可以写

def withTimeout(timeout: Duration)(service: HttpService[IO]): HttpService[IO] = timeout match {
    case finite: FiniteDuration => Timeout(finite)(service)
    case _                      => service
}

它应该编译。