Es könnte möglich sein, dies mit vorhandenen Klassen in Shapeless (etwas wie NatTRel
und RemoveAll
) zu tun, aber ich bin nicht 100% sicher, und das ist ein Fall, wo ich nur meinen eigenen Typ schreiben würde Klasse:
import shapeless._
trait OptionalPieces[L <: HList, S <: HList] {
def apply(l: L): Option[S]
}
object OptionalPieces extends LowPriorityOptionalPieces {
implicit val hnilOptionalPieces: OptionalPieces[HNil, HNil] =
new OptionalPieces[HNil, HNil] {
def apply(l: HNil): Option[HNil] = Some(HNil)
}
implicit def hconsOptionalPiecesMatch[H, T <: HList, S <: HList](implicit
opt: OptionalPieces[T, S]
): OptionalPieces[Option[H] :: T, H :: S] =
new OptionalPieces[Option[H] :: T, H :: S] {
def apply(l: Option[H] :: T): Option[H :: S] = for {
h <- l.head
t <- opt(l.tail)
} yield h :: t
}
}
sealed class LowPriorityOptionalPieces {
implicit def hconsOptionalPiecesNoMatch[H, T <: HList, S <: HList](implicit
opt: OptionalPieces[T, S]
): OptionalPieces[Option[H] :: T, S] =
new OptionalPieces[Option[H] :: T, S] {
def apply(l: Option[H] :: T): Option[S] = opt(l.tail)
}
}
diese Zeugen, dass L
mindestens in Option
, gewickelt, um alle Elemente der S
enthält, und gibt Ihnen einen Weg, um sie zur Laufzeit (sicher) auszupacken.
Wir können dann eine Syntax Helfer Klasse wie folgt definieren:
implicit class OptionalPiecesSyntax[A, R <: HList](a: A)(implicit
gen: Generic.Aux[A, R]
) {
def to[S <: HList](implicit op: OptionalPieces[gen.Repr, S]): Option[S] =
op(gen.to(a))
}
Und dann:
scala> val f1 = Foo(Some(1) , None, Some(3D))
f1: Foo = Foo(Some(1),None,Some(3.0))
scala> val f2 = Foo(None, Some("foo"), None)
f2: Foo = Foo(None,Some(foo),None)
scala> val result1 = f1.to[Int :: Double :: HNil]
result1: Option[shapeless.::[Int,shapeless.::[Double,shapeless.HNil]]] = Some(1 :: 3.0 :: HNil)
scala> val result2 = f2.to[String :: HNil]
result2: Option[shapeless.::[String,shapeless.HNil]] = Some(foo :: HNil)
Wenn Sie wirklich Ausnahmen wollten, die Sie gerade .get
in der Syntax Klasse nennen könnte, aber das scheint eine schlechte Idee zu sein.
Was möchten Sie in z. der 'f1.to [String :: HNil]' Fall? Es ist sicherlich möglich, dies zu tun, aber Sie müssen entscheiden, wie Sie mit dem Fall umgehen, in dem fehlende Ness nur zur Laufzeit bekannt ist. –
ich denke - Ausnahme, aber mögliche Rückkehr Option [T <: HList] wie in formlosen 'cast', und im Fall' f1.to [String :: HNil] 'zurück keine – mike