首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >缓存circe隐式解析的编码器/解码器实例

缓存circe隐式解析的编码器/解码器实例
EN

Stack Overflow用户
提问于 2019-01-29 06:17:42
回答 1查看 319关注 0票数 1

我使用circe来序列化/反序列化一些相当大的模型,其中每个叶子字段都是一个强类型(例如case class FirstName(value: String) extends AnyVal)。

EncoderDecoder的隐式解析/派生速度很慢。

我有自己的编解码器,我为它添加了一些额外的EncoderDecoder实例:

代码语言:javascript
复制
trait JsonCodec extends AutoDerivation {
    // ...
}

使用以下方法来帮助解码:

代码语言:javascript
复制
package json extends JsonCodec {

  implicit class StringExtensions(val jsonString: String) extends AnyVal {
    def decodeAs[T](implicit decoder: Decoder[T]): T =
      // ...
  }

}

问题是,每次我调用decodeAs时,它都会隐式地派生一个Decoder,这会导致编译时间大量增加。

有没有什么方法可以(一般地)缓存隐式,使其只生成一次Decoder

EN

回答 1

Stack Overflow用户

发布于 2019-01-29 13:44:17

为什么你不能泛泛地这么做

这是不可能的,因为您所请求的内容归结为缓存def。部分问题是,生成隐式实例可能会有副作用(尽管它很少这样做)。病理示例:

代码语言:javascript
复制
scala> var myVar: Int = 0
myVar: Int = 0

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait DummyTypeclass[T] { val counter: Int }
implicit def dummyInstance[T]: DummyTypeclass[T] = {
  myVar += 1
  new DummyTypeclass[T] {
    val counter = myVar
  }
}

// Exiting paste mode, now interpreting.

defined trait DummyTypeclass
dummyInstance: [T]=> DummyTypeclass[T]

scala> implicitly[DummyTypeclass[Int]].count
res1: Int = 1

scala> implicitly[DummyTypeclass[Boolean]].counter
res2: Int = 2

scala> implicitly[DummyTypeclass[Int]].counter
res3: Int = 3

正如你所看到的,缓存DummyTypeclass[Int]的值会破坏它的“功能”。

下一个最好的事情

第二个最好的方法是手动缓存一堆类型的实例。为了避免样板文件,我推荐使用ShapelesscachedImplicit宏。对于您的解码器示例,您最终会得到:

代码语言:javascript
复制
package json extends JsonCodec {

  import shapeless._

  implicit val strDecoder:  Decoder[String]    = cachedImplicit
  implicit val intDecoder:  Decoder[Int]       = cachedImplicit
  implicit val boolDecoder: Decoder[Boolean]   = cachedImplicit
  implicit val unitDecoder: Decoder[Unit]      = cachedImplicit
  implicit val nameDecoder: Decoder[FirstName] = cachedImplicit
  // ...

  implicit class StringExtensions(val jsonString: String) extends AnyVal {
    // ...
  }

}

如果您不喜欢宏,您可以手动执行此操作(基本上就是无形宏所做的操作),但它可能没有那么有趣。这使用了一个鲜为人知的技巧,隐含的可以通过隐藏他们的名字来“隐藏”。

代码语言:javascript
复制
package json extends JsonCodec {

  implicit val strDecoder:  Decoder[String] = {
    def strDecoder = ???
    implicitly[Decoder[String]]
  }
  implicit val intDecoder:  Decoder[Int] = {
    def intDecoder = ???
    implicitly[Decoder[Int]]
  }
  // ...

}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54411094

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档