我有以下示例代码:
import java.util.UUID
import shapeless.LabelledGeneric
import shapeless.record._
import shapeless.syntax.singleton._
object LabelTest extends App {
case class IncomingThing(name: String, age: Int)
case class DatabaseIncomingThing(name: String, age: Int, id: UUID)
val genIncoming = LabelledGeneric[IncomingThing]
val genDatabase = LabelledGeneric[DatabaseIncomingThing]
val thing = IncomingThing("John", 42)
val structuralVersionOfIncomingThing = genIncoming.to(thing)
val updated = genDatabase.from(structuralVersionOfIncomingThing + ('id ->> UUID.randomUUID()))
println(updated) // DatabaseIncomingThing(John,42,a45081f2-4ed5-4d2b-8fd9-4d8986875ed7)
}
这很不错,因为我不必编写用于复制从IncomingThing
到DatabaseIncomingThing
的所有字段的样板。但是,我希望不必同时维护这两种类型,因为两者之间的关系非常明确(一个拥有id
,另一个没有)。
是否可以通过添加或删除一个字段从给定的案例类创建类型? 我想像
type IncomingThing = withoutField[DatabaseIncomingThing]('id)
或类似的东西。
答案 0 :(得分:0)
代替DatabaseIncomingThing
val updated: DatabaseIncomingThing =
genDatabase.from(structuralVersionOfIncomingThing + ('id ->> UUID.randomUUID()))
您可以使用原始的HList
val updated1: FieldType[Witness.`'name`.T, String] :: FieldType[Witness.`'age`.T, Int] :: FieldType[Witness.`'id`.T, UUID] :: HNil =
structuralVersionOfIncomingThing + ('id ->> UUID.randomUUID())
val updated2: FieldType[Witness.`'name`.T, String] :: FieldType[Witness.`'age`.T, Int] :: HNil =
updated1 - 'id
在文字级别
implicitly[Remover.Aux[FieldType[Witness.`'name`.T, String] :: FieldType[Witness.`'age`.T, Int] :: FieldType[Witness.`'id`.T, UUID] :: HNil,
Witness.`'id`.T,
(UUID, FieldType[Witness.`'name`.T, String] :: FieldType[Witness.`'age`.T, Int] :: HNil)]]
implicitly[Updater.Aux[
FieldType[Witness.`'name`.T, String] :: FieldType[Witness.`'age`.T, Int] :: HNil,
FieldType[Witness.`'id`.T, UUID],
FieldType[Witness.`'name`.T, String] :: FieldType[Witness.`'age`.T, Int] :: FieldType[Witness.`'id`.T, UUID] :: HNil]]
您可以创建类型类
trait WithoutField[A, K] {
type Out <: HList
}
object WithoutField {
type Aux[A, K, Out0 <: HList] = WithoutField[A, K] { type Out = Out0 }
def instance[A, K, Out0 <: HList]: Aux[A, K, Out0] = new WithoutField[A, K] { type Out = Out0 }
implicit def mkWithoutField[A, L <: HList, K, T, L1 <: HList](implicit
labelledGeneric: LabelledGeneric.Aux[A, L],
remover: Remover.Aux[L, K, (T, L1)]): Aux[A, K, L1] = instance
}
并使用它
def foo[Out <: HList](implicit withoutField: WithoutField.Aux[DatabaseIncomingThing, Witness.`'id`.T, Out]) = {
// now you can use type Out inside
type IncomingThing = Out
???
}