İşte çoğu kez denenmemiş bir çözüm. Sonra
trait LowPriorityFromMap {
implicit def hconsFromMap1[K <: Symbol, V, T <: HList](implicit
witness: Witness.Aux[K],
typeable: Typeable[V],
fromMapT: Lazy[FromMap[T]]
): FromMap[FieldType[K, V] :: T] = new FromMap[FieldType[K, V] :: T] {
def apply(m: Map[String, Any]): Option[FieldType[K, V] :: T] = for {
v <- m.get(witness.value.name)
h <- typeable.cast(v)
t <- fromMapT.value(m)
} yield field[K](h) :: t
}
}
object FromMap extends LowPriorityFromMap {
implicit val hnilFromMap: FromMap[HNil] = new FromMap[HNil] {
def apply(m: Map[String, Any]): Option[HNil] = Some(HNil)
}
implicit def hconsFromMap0[K <: Symbol, V, R <: HList, T <: HList](implicit
witness: Witness.Aux[K],
gen: LabelledGeneric.Aux[V, R],
fromMapH: FromMap[R],
fromMapT: FromMap[T]
): FromMap[FieldType[K, V] :: T] = new FromMap[FieldType[K, V] :: T] {
def apply(m: Map[String, Any]): Option[FieldType[K, V] :: T] = for {
v <- m.get(witness.value.name)
r <- Typeable[Map[String, Any]].cast(v)
h <- fromMapH(r)
t <- fromMapT(m)
} yield field[K](gen.from(h)) :: t
}
}
Ve yardımcı kolaylık sınıfı::
import shapeless._, labelled.{ FieldType, field }
trait FromMap[L <: HList] {
def apply(m: Map[String, Any]): Option[L]
}
Sonra örneklerini:
class ConvertHelper[A] {
def from[R <: HList](m: Map[String, Any])(implicit
gen: LabelledGeneric.Aux[A, R],
fromMap: FromMap[R]
): Option[A] = fromMap(m).map(gen.from(_))
}
def to[A]: ConvertHelper[A] = new ConvertHelper[A]
Ve örnek:
case class Address(street: String, zip: Int)
case class Person(name: String, address: Address)
val mp = Map(
"name" -> "Tom",
"address" -> Map("street" -> "Jefferson st", "zip" -> 10000)
)
tip sınıf için İlk
Son olarak:
scala> to[Person].from(mp)
res0: Option[Person] = Some(Person(Tom,Address(Jefferson st,10000)))
Bu yalnızca üyeleri üyeleri ya Typeable
veya başka vaka sınıfları, ya Typeable
veya başka vaka sınıfları vardır vaka sınıfları için çalışacaktır ... (ve benzeri).
Örneğin aşağıdaki şekilde değiştirilmesi işe yaramıyor gibi gözüküyor. Herhangi bir fikir? 'vaka sınıf Adresi (sokak: String, zip: Int, devlet: String)' 'val mp = Harita ( "adı" -> "Tom", "adres" -> Harita ("sokak" -> "Jefferson st", "zip" -> 10000, "state" -> "CA") – lambdista
@lambdista Bir sapma meselesiydi - daha sağlam olması için cevabı düzenledim. –
@TravisBrown Haritanın bazı değerlerinin "boş" olmasına izin vermek için bu nasıl uyarlanabilir? Örneğin, "zip" -> null'. – ISJ