我有一个服务,它看起来像这样:
无标签的最后特征:
trait ProvisioningAPIService[M[_]] {
def provisionAPI(request: Request): M[Response]
}
在我的实现中,我有以下内容:
class ProvisioningService extends ProvisioningAPIService[Task] {
def provisionAPI(request: Request): Task[Response] = Task {
Response("response from server")
}
}
这很好,但我仍然希望延迟,并仅在实例化ProvisioningService的新版本时传递效果。例如我想要这样的东西:
class ProvisioningService[M[_]: Monad](implicit monad: Monad[M[_]) extends ProvisioningAPIService[M] {
def provisionAPI(request: Request): M[Response] = /* some wrapper that would be resolved at runtime */ {
Response("response from server")
}
}
在运行时,我会执行以下操作:
val privisioingServiceAsTask = new ProvisioningService[Task]
因此,基本上我不会在编译时提供具体的实现,但我会创建一个在运行时传递效果的ProvisioningService实例。我该怎么做?
将注释移动到答案,
说class MyClass[A : Monad]
和说class MyClass[A](implicit m: Monad[A])
是完全一样的,所以你不需要两者。在这种情况下,你实际上希望能够直呼其名,所以你应该更喜欢后者。
您可以在这里阅读Scala 3和Scala 2的上下文边界
现在让我们看看什么类型的类。类型类本质上以一种很好的方式实现了基于每个类型的重载。
因此,当您说在作用域中定义了Monad[A]
时,这意味着A
将定义Monad
特性包含的3个操作。实现的细节被抽象掉了,所以我们不必担心它们。如果您查看Monad的页面,并扩展为Applicative,您会发现Monad的任何实例都要求您具有Pure
的实现,该实现将值封装在类型构造函数中。对于给定的效果,这个pure
所做的将留给实例的实现。例如,它可以是Future.successful
。
所以你可以有一些类似的东西
import cats._
import cats.effect.IO
case class Request(s: String)
case class Response(s: String)
trait ProvisioningAPIService[M[_]] {
def provisionAPI(request: Request): M[Response]
}
class ProvisioningService[M[_]](implicit monad: Monad[M]) extends ProvisioningAPIService[M] {
def provisionAPI(request: Request): M[Response] = monad.pure(Response("response from server"))
}
val privisioingServiceAsTask = new ProvisioningService[IO]
希望这能回答你的问题