Почему вы не можете сделать это вообще
Это невозможно, поскольку то, что вы просите, сводится к кешированию 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
из Shapeless .Для вашего примера декодера вы получите:
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 {
// ...
}
}
Если вам не нравятся макросы, вы можете сделать это вручную (в основном то, что делает макрос Shapeless), но это может быть не так весело.Это использует малоизвестный трюк, который подразумевает, что последствия могут быть «скрыты», скрывая их имя.
package json extends JsonCodec {
implicit val strDecoder: Decoder[String] = {
def strDecoder = ???
implicitly[Decoder[String]]
}
implicit val intDecoder: Decoder[Int] = {
def intDecoder = ???
implicitly[Decoder[Int]]
}
// ...
}