簡體   English   中英

無形轉換案例類到HList並跳過所有選項字段

[英]shapeless convert case class to HList and skip all option fields

我有下一堂課:

case class Foo(a: Option[Int], b: Option[String], c: Option[Double])

正如您所看到的,所有字段都是可選的,我希望將此類轉換為HList或Tuple,就像

val f1 = Foo(Some(1) , None, Some(3D))
val f2 = Foo(None, "foo")

val result1 = f1.to[Int::Double::HNil] // => 1::3D
val result2 = f2.to[String::HNil] // "foo"

沒有反思可能嗎?

有可能使用Shapeless中的現有類型類(類似於NatTRelRemoveAll )來執行此操作,但我不是百分之百確定,並且這是我只編寫自己的類型類的情況:

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)
    }
}

這證明了L 至少包含了Option包含的S所有元素,並且為您提供了一種在運行時(安全地)解包它們的方法。

然后我們可以定義一個語法助手類,如下所示:

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))
}

然后:

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)

如果你真的想要異常,你可以在語法類中調用.get ,但這似乎是一個壞主意。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM