Gegeben:
%Vor% Ich möchte nur ein Foo
nur konstruieren, wenn mindestens eines seiner Argumente Some
ist, d. h. nicht alle Felder sind None
.
Es wäre ziemlich viel Code, um einen algebraischen Datentyp zu schreiben und dann Unterklassen für jede Variante zu erstellen:
%Vor% Gibt es einen saubereren, d. h. weniger Code, um mein Problem mit shapeless
zu lösen?
Dank des sealed abstract case class
Tricks, den Rob Norris kürzlich veröffentlicht hat , können Sie die Eigenschaften Ihres Foo
beibehalten. Fallklasse, sondern auch einen eigenen intelligenten Konstruktor, der ein Option[Foo]
zurückgibt, je nachdem, ob die angegebenen Argumente alle Kriterien erfüllen oder nicht:
Sie können so etwas mit verschachteltem Ior
s:
Jetzt ist es unmöglich, ein Foo
mit allen None
s zu erstellen. Sie könnten den Case-Klassenkonstruktor auch privat machen und die Ior
-Logik in einem alternativen Konstruktor auf dem Companion-Objekt passieren lassen, was die Mustererkennung ein wenig schöner machen würde, aber das Beispiel würde auch ein wenig länger machen.
Leider ist das ziemlich klobig zu benutzen. Was Sie wirklich wollen, ist eine Verallgemeinerung von Ior
in der gleichen Weise wie shapeless.Coproduct
eine Verallgemeinerung von Either
ist. Mir ist allerdings keine vorgefertigte Version von etwas ähnlichem bekannt.
Ich würde empfehlen, ein Builder-Muster für Ihre Klasse bereitzustellen. Dies ist besonders nützlich, wenn die Benutzer Ihrer Bibliothek normalerweise nur einige der vielen optionalen Parameter angeben. Und als Bonus mit den separaten Methoden pro Parameter müssen sie nicht alles in Some
Sie können einen einzelnen Typparameter für die Klasse verwenden, um zu markieren, ob dieser abgeschlossen ist (d. h. mindestens einen Some
-Parameter hat), und Sie können dies mit einem impliziten Parameter auf der Erstellungsmethode erzwingen.
Ich habe vorher mit einem typsicheren Builder experimentiert. Dieser Kernpunkt hat ein komplexeres Beispiel, obwohl auch hier verfolgt wird, welches Feld gesetzt wurde, damit es später ohne einen unsicheren Aufruf von Option.get
extrahiert werden kann.
Ссылка