简体   繁体   English

由于具有非值字段的类,隐式缺少 codec.Codec[Command]

[英]Missing scodec.Codec[Command] implicit because of class with non-value fields

I'm trying to use discriminators in existing project and something is wrong with my classes I guess.我正在尝试在现有项目中使用鉴别器,我猜我的课程有问题。

Consider this scodec example .考虑这个编解码器示例 If I change TurnLeft and its codec to如果我将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)

I get我得到

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

It all works if I make degrees field value field.如果我制作degrees字段值字段,这一切都有效。 I suspect it's something tricky with shapeless.我怀疑无形的东西很棘手。 What should I do to make it work ?我该怎么做才能让它发挥作用?

Sample project that demonstrates the issue is here .演示该问题的示例项目是here

shapeless's Generic is defined for "case-class-like" types. shapeless 的Generic是为“case-class-like”类型定义的。 To a first approximation, a case-class-like type is one whose values can be deconstructed to it's constructor parameters which can then be used to reconstruct an equal value, ie.对于第一个近似值,case-class-like 类型的值可以解构为它的构造函数参数,然后可以用于重建相等的值,即。

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

Case classes with a single constructor parameter list meet this criterion, whereas classes which don't have public (lazy) vals for their constructor parameters, or a companion with a matching apply / unapply , do not.具有单个构造函数参数列表的 Case 类满足此标准,而没有为其构造函数参数提供公共(惰性)val 的类,或具有匹配apply / unapply的伴随类,则不符合此标准。

The implementation of Generic is fairly permissive, and will treat (lazy) val members which correspond to constructor parameters (by type and order) as being equivalent to accessible constructor arguments, so the closest to your example that we can get would be something like this, Generic的实现是相当宽松的,并且会将与构造函数参数(按类型和顺序)对应的(懒惰)val 成员视为等同于可访问的构造函数参数,因此我们可以获得的最接近您的示例是这样的,

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

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

In this case getDegrees is treated as the accessor for the single Int constructor parameter.在这种情况下, getDegrees被视为单个Int构造函数参数的访问器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM