我有很多类似的案例类,它们意味着不同的东西但具有相同的参数列表.
object User {
case class Create(userName:String, firstName: String, lastName: String)
case class Created(userName:String, firstName: String, lastName: String)
}
object Group {
case class Create(groupName:String, members: Int)
case class Created(groupName:String, members: Int)
}
Run Code Online (Sandbox Code Playgroud)
鉴于这种设置,我厌倦了编写采用Create类型的参数并返回Created类型的参数的方法.我有大量的测试用例正是这样做的.
我可以写一个函数将一个case类转换成另一个case类.此功能转换User.Create为User.Created
def userCreated(create: User.Create) = User.Create.unapply(create).map((User.Created.apply _).tupled).getOrElse(sys.error(s"User creation failed: $create"))
Run Code Online (Sandbox Code Playgroud)
我不得不为Group编写另一个这样的函数.我真正想要的是一个泛型函数,它接受两种类型的case类和一个case类的对象并转换为另一个.就像是,
def transform[A,B](a: A):B
Run Code Online (Sandbox Code Playgroud)
此外,该功能不应该破坏减少样板的目的.如果更容易使用,请随意为功能建议不同的签名.
Rya*_*yan 10
无形的救援!
您可以使用Shapeless Generic来创建案例类的通用表示,然后可以使用它来完成您尝试执行的操作.使用LabelledGeneric我们可以强制执行类型和参数名称.
import shapeless._
case class Create(userName: String, firstName: String, lastName: String)
case class Created(userName: String, firstName: String, lastName: String)
case class SortOfCreated(screenName: String, firstName: String, lastName: String)
val c = Create("username", "firstname", "lastname")
val createGen = LabelledGeneric[Create]
val createdGen = LabelledGeneric[Created]
val sortOfCreatedGen = LabelledGeneric[SortOfCreated]
val created: Created = createdGen.from(createGen.to(c))
sortOfCreatedGen.from(createGen.to(c)) // fails to compile
Run Code Online (Sandbox Code Playgroud)
为了记录,这里是我设法实现的最简单的类型安全语法:
implicit class Convert[A, RA](value: A)(implicit ga: Generic.Aux[A, RA]) {
def convertTo[B, RB](gb: Generic.Aux[B, RB])(implicit ev: RA =:= RB) =
gb.from(ga.to(value))
}
Run Code Online (Sandbox Code Playgroud)
它可以像这样使用:
case class Create(userName: String, firstName: String, lastName: String)
case class Created(userName: String, firstName: String, lastName: String)
val created = Create("foo", "bar", "baz").convertTo(Generic[Created])
Run Code Online (Sandbox Code Playgroud)
或者同样的事情LabelledGeneric来实现更好的类型安全性:
implicit class Convert[A, RA](value: A)(implicit ga: LabelledGeneric.Aux[A, RA]) {
def convertTo[B, RB](gb: LabelledGeneric.Aux[B, RB])(implicit ev: RA =:= RB) =
gb.from(ga.to(value))
}
val created = Create("foo", "bar", "baz").convertTo(LabelledGeneric[Created]))
Run Code Online (Sandbox Code Playgroud)