2017-02-02 2 views
2

J'essaie d'utiliser des discriminateurs dans le projet existant et quelque chose ne va pas avec mes classes je suppose.Missing scodec.Codec [Command] implicite à cause de la classe avec des champs sans valeur

Considérez ceci scodec example. Si je change TurnLeft et son codec à

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

Je reçois

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

tout cela fonctionne si je fais champ de valeur du champ degrees. Je soupçonne que c'est quelque chose de difficile avec Shapeless. Que dois-je faire pour le faire fonctionner?

Exemple de projet qui illustre le problème: here.

Répondre

1

La forme Generic de shapeless est définie pour les types de type "case-class". En première approximation, un type de type case-class est un type dont les valeurs peuvent être décomposées en paramètres constructeurs qui peuvent alors être utilisés pour reconstruire une valeur égale, ie.

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

classes de cas avec une seule liste de paramètres constructeur répondent à ce critère, alors que les classes qui ne sont pas vals publiques (paresseux) pour leurs paramètres du constructeur, ou un compagnon avec un apply/unapply correspondant, non. L'implémentation de Generic est assez permissive, et traitera les membres val (paresseux) qui correspondent aux paramètres constructeurs (par type et par ordre) comme étant équivalents aux arguments constructeurs accessibles, donc le plus proche de votre exemple que nous pouvons obtenir serait est considéré comme l'accesseur pour le seul paramètre constructeur Int quelque chose comme ça,

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

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

Dans ce cas getDegrees.

+0

Génial! Merci, Miles. Question secondaire à ce sujet. La définition de ces vals va-t-elle doubler l'empreinte mémoire d'une classe donnée? – expert

+0

Il n'y a qu'un seul val ici: l'argument constructeur d'une classe non-case ne génère pas de val sauf s'il est explicitement marqué comme tel. –

+0

Je vois. J'ai supposé qu'il devait encore être stocké quelque part si '' '' '' '' '' '' – expert