Отсутствует scodec.Codec[Command] неявно из-за класса с не значащими полями

Я пытаюсь использовать дискриминаторы в существующем проекте, и что-то не так с моими классами, я думаю.

Рассмотрим этот пример scodec. Если я изменю TurnLeft и его кодек для

sealed class TurnLeft(degrees: Int) extends Command {
  def getDegrees: Int = degrees
}
implicit val leftCodec: Codec[TurnLeft] = uint8or16.xmap[TurnLeft](v => new TurnLeft(v), _.getDegrees)

я получил

Error:(x, x) could not find Lazy implicit value of type scodec.Codec[Command]
    val codec: Codec[Either[UnrecognizedCommand, Command]] = discriminatorFallback(unrecognizedCodec, Codec[Command])

Все работает, если я сделаю degrees поле значения поля. Я подозреваю, что с бесформенным это сложно. Что я должен сделать, чтобы это работало?

Пример проекта, который демонстрирует проблему, находится здесь.

1 ответ

Решение

Бесформенный -х Generic определен для "case-class-like" типов. В первом приближении тип, подобный классу случая, - это тип, значения которого могут быть деконструированы до его параметров конструктора, которые затем могут быть использованы для восстановления равного значения, т.е.

case class Foo ...
val foo = Foo(...)
val fooGen = Generic[Foo]
assert(fooGen.from(fooGen.to(foo)) == foo)

Классы case с одним списком параметров конструктора соответствуют этому критерию, тогда как классы, которые не имеют открытых (ленивых) значений для своих параметров конструктора, или компаньон с соответствующим apply/unapply, не делайте.

Реализация Generic является довольно допустимым и будет обрабатывать (ленивые) члены val, которые соответствуют параметрам конструктора (по типу и порядку), как эквивалентные доступным аргументам конструктора, так что ближайший к вашему примеру, который мы можем получить, будет что-то вроде этого,

sealed class TurnLeft(degrees: Int) extends Command {
  val getDegrees: Int = degrees
}

scala> Generic[TurnLeft]
res0: shapeless.Generic[TurnLeft]{type Repr = Int :: HNil } = ...

В этом случае getDegrees рассматривается как средство доступа для одного Int параметр конструктора.

Другие вопросы по тегам