使用 Shapeless 从 case class 派生新类型
Derive new type from case class using 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]
所以再一次,问题是,有没有办法(即使用 shapeless)创建具有此类字段的派生案例 class(无需编写宏来做到这一点。)
Case 类只是 HList。我们可以基于某种类型的 HList 创建一个新类型吗?
您无法生成 de novo 具体类型,除非使用宏注释。您可以做的是使用类型class 派生具有您想要的转换形状的泛型。
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
类型添加一些功能class(鉴于名称,可能是一种类似镜头的方法,将选项表示的增量应用到类型 L
), 因为就目前而言,该类型有点无用。在某些方面,记录表示不如 case class 好,但它可以与其他基于无形的东西很好地互操作(例如,使用类似的技术来喷射 -json 会很容易) -shapeless 将 JSON 反序列化为 GenericUserUpdate
)
假设我有
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]
所以再一次,问题是,有没有办法(即使用 shapeless)创建具有此类字段的派生案例 class(无需编写宏来做到这一点。)
Case 类只是 HList。我们可以基于某种类型的 HList 创建一个新类型吗?
您无法生成 de novo 具体类型,除非使用宏注释。您可以做的是使用类型class 派生具有您想要的转换形状的泛型。
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
类型添加一些功能class(鉴于名称,可能是一种类似镜头的方法,将选项表示的增量应用到类型 L
), 因为就目前而言,该类型有点无用。在某些方面,记录表示不如 case class 好,但它可以与其他基于无形的东西很好地互操作(例如,使用类似的技术来喷射 -json 会很容易) -shapeless 将 JSON 反序列化为 GenericUserUpdate
)