Scala 如何在F多态代码中使用guave缓存加载程序
我有一个服务,这是一个笑话: 但我想先用guava cache来缓存请求的笑话(仅通过常量键,这无关紧要):Scala 如何在F多态代码中使用guave缓存加载程序,scala,scala-cats,http4s,cats-effect,Scala,Scala Cats,Http4s,Cats Effect,我有一个服务,这是一个笑话: 但我想先用guava cache来缓存请求的笑话(仅通过常量键,这无关紧要): object Jokes { def apply[F[_]](implicit ev: Jokes[F]): Jokes[F] = ev final case class Joke(joke: String) extends AnyRef object Joke { implicit val jokeDecoder: Decoder[Joke] = deriveDe
object Jokes {
def apply[F[_]](implicit ev: Jokes[F]): Jokes[F] = ev
final case class Joke(joke: String) extends AnyRef
object Joke {
implicit val jokeDecoder: Decoder[Joke] = deriveDecoder[Joke]
implicit def jokeEntityDecoder[F[_]: Sync]: EntityDecoder[F, Joke] =
jsonOf
implicit val jokeEncoder: Encoder[Joke] = deriveEncoder[Joke]
implicit def jokeEntityEncoder[F[_]: Applicative]: EntityEncoder[F, Joke] =
jsonEncoderOf
}
final case class JokeError(e: Throwable) extends RuntimeException
def impl[F[_]: Sync](C: Client[F]): Jokes[F] = new Jokes[F]{
val cacheLoader : CacheLoader[String, Joke] = new CacheLoader[String, Joke] {
override def load(key: String): Joke = {
import dsl._
val joke: F[Joke] = C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError{ case t => JokeError(t)}
//? F[Joke] => Joke
null
}
}
val cache = CacheBuilder.newBuilder().build(cacheLoader)
val dsl = new Http4sClientDsl[F]{}
def get: F[Jokes.Joke] = {
//it's ok?
cache.get("constant").pure[F]
}
}
}
如您所见,cacheLoader
需要“物化”值F[Joke]=>Joke
。和缓存返回纯值,不带F
如何在
F
polymorpic code中使用此缓存?您基本上是在询问如何在F
中运行代码多态性,为此,您需要对F
进行效果
约束
此外,您还需要使用延迟
,而不是使用纯
,因为从缓存中获取值是一种副作用
val cacheLoader : CacheLoader[String, Joke] = new CacheLoader[String, Joke] {
override def load(key: String): Joke = {
import dsl._
val joke: F[Joke] = C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError{ case t => JokeError(t)}
// This is a side effect, but can't avoid it due to the way the API is designed
joke.toIO.unsafeRunSync()
}
}
val cache = CacheBuilder.newBuilder().build(cacheLoader)
val dsl = new Http4sClientDsl[F]{}
def get: F[Jokes.Joke] = {
// This is okay :)
Sync[F].delay(cache.get("constant"))
}
另一方面,如果您想使用与http4s能够很好地互操作的东西,我强烈推荐mules
。在这里查看:
For me line
val cache=CacheBuilder.newBuilder().build(cacheLoader)
生成错误:(52,43)推断类型参数[String,io.chrisdavenport.clientexample.Jokes.Jokes.Jokes]不符合方法构建的类型参数界限[K1编辑扩展AnyVal
=>扩展AnyRef
。现在编译
val cacheLoader : CacheLoader[String, Joke] = new CacheLoader[String, Joke] {
override def load(key: String): Joke = {
import dsl._
val joke: F[Joke] = C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError{ case t => JokeError(t)}
// This is a side effect, but can't avoid it due to the way the API is designed
joke.toIO.unsafeRunSync()
}
}
val cache = CacheBuilder.newBuilder().build(cacheLoader)
val dsl = new Http4sClientDsl[F]{}
def get: F[Jokes.Joke] = {
// This is okay :)
Sync[F].delay(cache.get("constant"))
}