Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 缓存circe隐式解析的编码器/解码器实例_Scala_Implicit_Shapeless_Circe - Fatal编程技术网

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

Scala 缓存circe隐式解析的编码器/解码器实例,scala,implicit,shapeless,circe,Scala,Implicit,Shapeless,Circe,我使用circe对一些相当大的模型进行序列化/反序列化,其中每个叶字段都是强类型(例如,case class FirstName(value:String)扩展了AnyVal) 编码器或解码器的隐式解析/推导速度较慢 我有自己的编解码器,为此我添加了一些额外的编码器和解码器实例: trait JsonCodec extends AutoDerivation { // ... } 使用以下方法帮助解码: package json extends JsonCodec { implic

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

编码器
解码器
的隐式解析/推导速度较慢

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

trait JsonCodec extends AutoDerivation {
    // ...
}
使用以下方法帮助解码:

package json extends JsonCodec {

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

}
问题是,每次我调用
decodeAs
,它都会隐式派生一个
解码器
,这会导致编译时间大幅增加

是否有任何方法可以(一般地)缓存隐式,使其只生成一次
解码器
这是不可能的,因为您所要求的归结为缓存
def
。问题的一部分在于生成隐式实例可能(尽管很少)产生副作用。病理学示例:

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]
的值将破坏其“功能”

次好的事情 其次,最好是手动缓存一组类型的实例。为了避免样板文件,我建议使用中的
cachedImplicit
宏。对于您的解码器示例,您将得到:

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 {
    // ...
  }

}
如果您不喜欢宏,可以手动执行此操作(基本上与无形状宏相同),但可能没有那么有趣。这使用了一个鲜为人知的技巧,通过隐藏其名称可以“隐藏”

package json extends JsonCodec {

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

}

我不确定在您的
StringExtensions
类中是否可以。但是,无论何时调用
decodeAs
方法,都可以首先执行以下操作:
implicit val tDecoder:Decoder[T]=derieveDecoder
(使用自己的类型更改
T
)。这样,对
decodeAs[T]
的所有调用都将使用val,而不是派生新的解码器。注意:如果您的模型由许多嵌套类型组成,请按相反顺序为每个类型创建解码器。我认为Luis idea as不会保存任何内容,因为编译器仍然需要为每个
隐式val
生成所有这些
解码器。我能想到的唯一方法是将所有类型的解码器作为
implicit val
s放在一些全局已知的静态位置,比如
json
包对象本身。然后每次只能有一个这样的
隐式val
,编译器可以在每次需要这样的
解码器时使用这些一次派生的值(假设您将
导入到上下文中)。