使用运行时配置使参数化 ScalaCache 通用
Making parameterized ScalaCache generic with runtime configuration
可以在此处找到包含该问题的 git 存储库 https://github.com/mdedetrich/scalacache-example
我目前遇到的问题是我试图让我的 ScalaCache 后端不可知,因为它可以在运行时使用类型安全配置进行配置。
我遇到的问题是 ScalaCache 参数化了缓存的构造函数,即构造一个咖啡因缓存你会做
ScalaCache(CaffeineCache())
至于 SentinelRedisCache
你会怎么做
ScalaCache(SentinelRedisCache("", Set.empty, ""))
就我而言,我创建了一个名为 MyCache
的通用缓存包装器,如下所示
import scalacache.ScalaCache
import scalacache.serialization.Codec
final case class MyCache[CacheRepr](scalaCache: ScalaCache[CacheRepr])(
implicit stringCodec: Codec[Int, CacheRepr]) {
def putInt(value: Int) = scalaCache.cache.put[Int]("my_int", value, None)
}
我们需要携带 CacheRepr
,因为这是 ScalaCache 知道如何序列化任何类型的方式 T
。 CaffeineCache
使用 CacheRepr
即 InMemoryRepr
而 SentinelRedisCache
使用 CacheRepr
即 Array[Byte]
.
这就是问题的症结所在,我有一个 Config
只存储正在使用哪个缓存,即
import scalacache.Cache
import scalacache.caffeine.CaffeineCache
import scalacache.redis.SentinelRedisCache
final case class ApplicationConfig(cache: Cache[_])
它是 Cache[_]
的原因是因为在编译时我们不知道正在使用什么缓存,ApplicationConfig
将在运行时用 CaffeineCache
/SentinelRedisCache
.
这就是问题的症结所在,Scala 无法找到通配符类型的隐式 Codec
如果我们只使用 applicationConfig.cache
作为构造函数,即 https://github.com/mdedetrich/scalacache-example/blob/master/src/main/scala/Main.scala#L17
如果我们取消注释上面的行,我们会得到
[error] /Users/mdedetrich/github/scalacache-example/src/main/scala/Main.scala:17:37: Could not find any Codecs for type Int and _. Please provide one or import scalacache._
[error] Error occurred in an application involving default arguments.
[error] val myCache3: MyCache[_] = MyCache(ScalaCache(applicationConfig.cache)) // This doesn't
有谁知道如何解决这个问题,本质上我想在我的 ApplicationConfig
中指定缓存的类型是 Cache[InMemoryRepr | Array[Byte]]
而不仅仅是 Cache[_]
(这样 Scala编译器知道查找 InMemoryRepr or Array[Byte]
和 MyCache
的隐式定义,像这样
final case class MyCache[CacheRepr <: InMemoryRepr | Array[Byte]](scalaCache: ScalaCache[CacheRepr])
您似乎要求编译器根据缓存类型的 运行 时间选择来解析隐式值。这是不可能的,因为编译器在应用程序代码启动时不再 运行ning。
您必须在编译时进行类型解析,而不是 运行 时。所以你需要定义一个trait
表示缓存的抽象接口,并提供一个工厂函数,returns一个基于ApplicationConfig
中设置的特定实例。它可能看起来像这样(未经测试):
sealed trait MyScalaCache {
def putInt(value: Int)
}
object MyScalaCache {
def apply(): MyScalaCache =
if (ApplicationConfig.useCaffine) {
MyCache(ScalaCache(CaffeineCache())
} else {
MyCache(ScalaCache(SentinelRedisCache("", Set.empty, ""))
}
}
final case class MyCache[CacheRepr](scalaCache: ScalaCache[CacheRepr]) extends MyScalaCache (
implicit stringCodec: Codec[Int, CacheRepr]) {
def putInt(value: Int) = scalaCache.cache.put[Int]("my_int", value, None)
}
编译器将在编译时解析 MyCache
中的隐式,其中两个具体实例在 apply
中指定。
可以在此处找到包含该问题的 git 存储库 https://github.com/mdedetrich/scalacache-example
我目前遇到的问题是我试图让我的 ScalaCache 后端不可知,因为它可以在运行时使用类型安全配置进行配置。
我遇到的问题是 ScalaCache 参数化了缓存的构造函数,即构造一个咖啡因缓存你会做
ScalaCache(CaffeineCache())
至于 SentinelRedisCache
你会怎么做
ScalaCache(SentinelRedisCache("", Set.empty, ""))
就我而言,我创建了一个名为 MyCache
的通用缓存包装器,如下所示
import scalacache.ScalaCache
import scalacache.serialization.Codec
final case class MyCache[CacheRepr](scalaCache: ScalaCache[CacheRepr])(
implicit stringCodec: Codec[Int, CacheRepr]) {
def putInt(value: Int) = scalaCache.cache.put[Int]("my_int", value, None)
}
我们需要携带 CacheRepr
,因为这是 ScalaCache 知道如何序列化任何类型的方式 T
。 CaffeineCache
使用 CacheRepr
即 InMemoryRepr
而 SentinelRedisCache
使用 CacheRepr
即 Array[Byte]
.
这就是问题的症结所在,我有一个 Config
只存储正在使用哪个缓存,即
import scalacache.Cache
import scalacache.caffeine.CaffeineCache
import scalacache.redis.SentinelRedisCache
final case class ApplicationConfig(cache: Cache[_])
它是 Cache[_]
的原因是因为在编译时我们不知道正在使用什么缓存,ApplicationConfig
将在运行时用 CaffeineCache
/SentinelRedisCache
.
这就是问题的症结所在,Scala 无法找到通配符类型的隐式 Codec
如果我们只使用 applicationConfig.cache
作为构造函数,即 https://github.com/mdedetrich/scalacache-example/blob/master/src/main/scala/Main.scala#L17
如果我们取消注释上面的行,我们会得到
[error] /Users/mdedetrich/github/scalacache-example/src/main/scala/Main.scala:17:37: Could not find any Codecs for type Int and _. Please provide one or import scalacache._
[error] Error occurred in an application involving default arguments.
[error] val myCache3: MyCache[_] = MyCache(ScalaCache(applicationConfig.cache)) // This doesn't
有谁知道如何解决这个问题,本质上我想在我的 ApplicationConfig
中指定缓存的类型是 Cache[InMemoryRepr | Array[Byte]]
而不仅仅是 Cache[_]
(这样 Scala编译器知道查找 InMemoryRepr or Array[Byte]
和 MyCache
的隐式定义,像这样
final case class MyCache[CacheRepr <: InMemoryRepr | Array[Byte]](scalaCache: ScalaCache[CacheRepr])
您似乎要求编译器根据缓存类型的 运行 时间选择来解析隐式值。这是不可能的,因为编译器在应用程序代码启动时不再 运行ning。
您必须在编译时进行类型解析,而不是 运行 时。所以你需要定义一个trait
表示缓存的抽象接口,并提供一个工厂函数,returns一个基于ApplicationConfig
中设置的特定实例。它可能看起来像这样(未经测试):
sealed trait MyScalaCache {
def putInt(value: Int)
}
object MyScalaCache {
def apply(): MyScalaCache =
if (ApplicationConfig.useCaffine) {
MyCache(ScalaCache(CaffeineCache())
} else {
MyCache(ScalaCache(SentinelRedisCache("", Set.empty, ""))
}
}
final case class MyCache[CacheRepr](scalaCache: ScalaCache[CacheRepr]) extends MyScalaCache (
implicit stringCodec: Codec[Int, CacheRepr]) {
def putInt(value: Int) = scalaCache.cache.put[Int]("my_int", value, None)
}
编译器将在编译时解析 MyCache
中的隐式,其中两个具体实例在 apply
中指定。