使用Shapeless

时间:2016-05-20 13:10:09

标签: scala shapeless

我们说我有

case class User(id: Long, name: String, age: Long, email: Option[String])

有没有办法可以创造让我们说

type UpdateUser = ???.???[User] // update user has same fields as User except all are optional

然后我可以用作

UpdateUser(name = Some("foo"), email = Some("foo@bar.com"))

所以基本上是映射类型

Long         :: String         :: Long         :: Option[String] 
->
Option[Long] :: Option[String] :: Option[Long] :: Option[String]

再一次,问题是,有没有办法(即使用无形)用这样的字段创建这样的派生案例类(没有写宏来做那件事。)

案例分支只是HLists。我们可以根据某种类型的HList创建一个新类型吗?

1 个答案:

答案 0 :(得分:1)

除非使用宏注释,否则您无法生成 de novo 具体类型。你可以做的是使用类型类派生一个具有你想要的变换形状的泛型类型。

import shapeless._, labelled._

trait RecordAsOption[L] {
  type Out <: HList
}
object RecordAsOption {
  def apply[L](implicit recordAsOption: RecordAsOption[L])
      : Aux[L, recordAsOption.Out] =
    recordAsOption
  type Aux[L, Out0 <: HList] = RecordAsOption[L] { type Out = Out0 }
  implicit def hnilRecordAsOption[L <: HNil]: Aux[L, HNil] =
    new RecordAsOption[L] {
      type Out = HNil
      def apply(l: L) = HNil
    }

  implicit def hconsRecordAsOption[K, V, T <: HList](
      implicit tail: RecordAsOption[T])
      : Aux[FieldType[K, V] :: T, FieldType[K, Option[V]] :: tail.Out] =
    new RecordAsOption[FieldType[K, V] :: T] {
      type Out = FieldType[K, Option[V]] :: tail.Out
    }

  implicit def genericRecordAsOption[T, R](
    implicit lg: LabelledGeneric.Aux[T, R], roa: RecordAsOption[T])
      : Aux[T, roa.Out] =
    new RecordAsOption[T] {
      type Out = roa.Out
    }
}

case class User(id: Long, name: String, age: Long, email: Option[String])
val genericUserUpdate = RecordAsOption[User]
type GenericUserUpdate = genericUserUpdate.Out

您可能希望向RecordAsOption类型类添加一些功能(给定名称,可能是类似镜头的方法,将选项表示的增量应用于类型L的值),因为因为它的类型是有点无用的。记录表示在某些方面并不像案例类那么好,但是它可以与其他基于无形的东西很好地互操作(例如,使用类似的技术来喷涂-json-shapeless以将JSON反序列化为一个GenericUserUpdate