2016-11-06 24 views
5

tüm seçenek alanları atlamak:şekilsiz dönüştürme durumda hList sınıf ve önümüzdeki sınıf var

gibi

gördüğünüz gibi
case class Foo(a: Option[Int], b: Option[String], c: Option[Double]) 

, tüm alanlar isteğe bağlıdır, ben hList veya kayıt düzeni içine bu sınıf dönüştürmek istiyorum

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" 

Yansıma olmaksızın mümkün mü?

+1

Örneğin, örn. 'f1.to [String :: HNil]' davası? Bunu yapmak kesinlikle mümkün, ancak eksikliğin sadece çalışma zamanında bilindiği durumun nasıl ele alınacağına karar vermeniz gerekecek. –

+0

bence - istisna, ancak olası dönüş Seçenek [T <: HList] shapeless 'cast' gibi ve f1.to [String :: HNil] 'durumunda – mike

cevap

6

şekilsiz (NatTRel ve RemoveAll gibi bir şey) içinde mevcut tip sınıfları ile bunu yapmak mümkün olabilir, ama ben% 100 bundan emin değilim ve bu sadece benim kendi türünü yazacağımı bir durumdur sınıfı: L en az sırayla, Option sarılı S tüm öğelerini içerir ve size zamanında (güvenle) onları kakışıyor için bir yol verdiğini

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

Bu tanıklar. Eğer gerçekten istisnalar isteseydi sadece sözdizimi sınıfında .get diyebiliriz,

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) 

, ama bu: o zaman

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

Ve:

Sonra böyle bir sözdizimi yardımcı sınıf tanımlayabilirsiniz Kötü bir fikir gibi görünüyor.