Вы можете кэшировать LabelledGeneric
экземпляры Shapeless, например, так:
import shapeless.{LabelledGeneric, the}
case class MyModel(value: String) extends AnyVal
case class MyOtherModel(value: Int) extends AnyVal
case class MyRootModel(myModel: MyModel, myOtherModel: MyOtherModel)
object MyModel {
implicit val generic = the[LabelledGeneric[MyModel]]
}
object MyOtherModel {
implicit val generic = the[LabelledGeneric[MyOtherModel]]
}
object MyRootModel {
implicit val generic = the[LabelledGeneric[MyRootModel]]
}
Конечно, вы должны посмотреть, улучшает ли это время компиляции в вашем собственном проекте, но в качестве быстрого теста мы можем настроить тест, которыйразрешает LabelledGeneric
несколько раз (в данном случае тысячу раз):
object Test {
def foo0 = {
LabelledGeneric[MyRootModel]
LabelledGeneric[MyRootModel]
// repeat 98 more times...
}
def foo1 = {
LabelledGeneric[MyRootModel]
LabelledGeneric[MyRootModel]
// repeat 98 more times...
}
// and so on through foo9
}
(Обратите внимание, что мы должны разделить вызовы, потому что если мы просто сбросили тысячу из них в строке одним способомсгенерированный макросом будет превышать пределы размера метода JVM, когда мы закомментируем кеширование экземпляра для сравнения.)
На моем компьютере файл Test.scala
, содержащий Test
, определения класса case и кэшированныйэкземпляры компилируются примерно за 3 секунды.Если мы закомментируем определения generic
, это займет более 12 секунд.Это, конечно, довольно ненаучно, но это обнадеживает.
Обратите внимание, что в общем случае не стоит иметь implicit
определений без аннотации типа, и вы можете избежать этого для кэшированных экземпляров, написав что-товот так:
import shapeless.{LabelledGeneric, TypeOf, cachedImplicit}
case class MyModel(value: String) extends AnyVal
case class MyOtherModel(value: Int) extends AnyVal
case class MyRootModel(myModel: MyModel, myOtherModel: MyOtherModel)
object MyModel {
implicit val generic: TypeOf.`LabelledGeneric[MyModel]`.type = cachedImplicit
}
object MyOtherModel {
implicit val generic: TypeOf.`LabelledGeneric[MyOtherModel]`.type = cachedImplicit
}
object MyRootModel {
implicit val generic: TypeOf.`LabelledGeneric[MyRootModel]`.type = cachedImplicit
}
TypeOf
- это какая-то странная магия, и, честно говоря, когда мне нужно что-то подобное, я просто использовал подход the
.
В качестве сноски, так как вы упомянули специально о Circe, вы можете попробовать Circe-Derivation .Он работает в качестве замены для большей части функциональных возможностей circe-generic, но не основан на Shapeless и компилируется намного быстрее.