当前位置:网站首页>How to use 200 lines of code to implement Scala's Object Converter
How to use 200 lines of code to implement Scala's Object Converter
2022-06-27 13:22:00 【Dreamland blurred】
And CSV Converter similar , However, the type of treatment required this time is unpredictable , So the implementation is slightly different .
API Definition
trait Transformer[-From, +To] {
def transform(from: From): To
}
object Transformer {
def apply[From, To](implicit st: Transformer[From, To]): Transformer[From, To] = st
}
establish Transformer example
Yes API After that, we will realize API, This can be achieved in two ways :
- Use macro Generate .
- own new One .
The following only describes how to generate macros .
Use macro Generate
Defining macro DSL
object Transformable {
def apply[From <: Product, To <: Product]: Transformable[From, To] =
macro TransformerMacro.applyImpl[From, To]
}
Provide setName and setType Two methods , Provide compile time mapping for field names and types respectively :
/** @author * The dream is blurred * @version 1.0,6/15/22 */
class Transformable[From, To] {
@unchecked
def setType[FromField, ToField](
selectFromField: From => FromField,
map: FromField => ToField
): Transformable[From, To] =
macro TransformerMacro.mapTypeImpl[From, To, FromField, ToField]
@unchecked
def setName[FromField, ToField](
selectFromField: From => FromField,
selectToField: To => ToField
): Transformable[From, To] =
macro TransformerMacro.mapNameImpl[From, To, FromField, ToField]
def instance: Transformer[From, To] = macro TransformerMacro.instanceImpl[From, To]
}
So used :
case class A1(a: String, b: Int, cc: Long, d: Option[String])
case class A2(a: String, b: Int, c: Int, d: Option[String])
val a = A1("hello", 1, 2, None)
val b: A2 = Transformable[A1, A2]
.setName(_.cc, _.c)
.setType[Long, Int](_.cc, fromField => if (fromField > 0) fromField.toInt else 0)
.instance
.transform(a)
b.toString shouldEqual "A2(hello,1,2,None)"
principle
- Store... During compilation
setNameandsetTypeThe mapping relation of , And call the mapping function when the types are incompatible . - utilize implicit, According to need , Will automatically search for and apply qualified
TransformerImplicit value . setTypeIt's not necessary , Because the default searchimplicit Transformer[From, To], If not, you need to usesetType, But if you have definedimplicit Transformer[From, To], You don't need to , howeversetTypeHigher priority , Will be covered implicit.
Super complex structure :
case class C1(j: Int)
case class D1(
a1: List[List[C1]],
b1: Option[C1],
c1: List[Option[C1]],
d1: Option[List[C1]],
map1: Map[String, String],
intMap1: Map[Int, C1]
)
case class C2(j: Int)
case class D2(
a2: List[List[C2]],
b2: Option[C1],
c2: List[Option[C1]],
d2: Option[List[C1]],
map2: Map[String, String],
intMap2: Map[Int, C2]
)
// NOTE: have collection not support? please implicit val transformer = new Transformer[F, T] { ... }
object C1 {
// Once defined, you do not need to use setType The method
implicit val cTransformer: Transformer[C1, C2] = Transformable[C1, C2].instance
}
object D1 {
implicit val dTransformer: Transformer[D1, D2] = Transformable[D1, D2]
.setName(_.a1, _.a2)
.setName(_.b1, _.b2)
.setName(_.c1, _.c2)
.setName(_.d1, _.d2)
.setName(_.map1, _.map2)
.setName(_.intMap1, _.intMap2)
.instance
}
val d1 = D1(
List(List(C1(1))),
Option(C1(2)),
List(Option(C1(3))),
Option(List(C1(4))),
Map("hello" -> "world"),
Map(1 -> C1(1))
)
val d2: D2 = Transformer[D1, D2].transform(d1)
println(d2)
d2.toString shouldBe "D2(List(List(C2(1))),Some(C1(2)),List(Some(C1(3))),Some(List(C1(4))),Map(hello -> world),Map(1 -> C2(1)))"
This is because common collections are provided by default , Therefore, the client does not need to define the Transformer:
implicit final def transformerOption[F, T](implicit e: Transformer[F, T]): Transformer[Option[F], Option[T]] =
new Transformer[Option[F], Option[T]] {
override def transform(from: Option[F]): Option[T] = from.map(e.transform)
}
implicit final def transformerSeq[F, T](implicit e: Transformer[F, T]): Transformer[Seq[F], Seq[T]] =
new Transformer[Seq[F], Seq[T]] {
override def transform(from: Seq[F]): Seq[T] = from.map(e.transform)
}
implicit final def transformerSet[F, T](implicit e: Transformer[F, T]): Transformer[Set[F], Set[T]] =
new Transformer[Set[F], Set[T]] {
override def transform(from: Set[F]): Set[T] = from.map(e.transform)
}
implicit final def transformerList[F, T](implicit e: Transformer[F, T]): Transformer[List[F], List[T]] =
new Transformer[List[F], List[T]] {
override def transform(from: List[F]): List[T] = from.map(e.transform)
}
implicit final def transformerVector[F, T](implicit e: Transformer[F, T]): Transformer[Vector[F], Vector[T]] =
new Transformer[Vector[F], Vector[T]] {
override def transform(from: Vector[F]): Vector[T] = from.map(e.transform)
}
implicit final def transformerMap[K, F, T](implicit
e: Transformer[F, T]
): Transformer[Map[K, F], Map[K, T]] =
new Transformer[Map[K, F], Map[K, T]] {
override def transform(from: Map[K, F]): Map[K, T] = from.map(kv => kv._1 -> e.transform(kv._2))
}
implicit final def transformerSeqList[F, T](implicit e: Transformer[F, T]): Transformer[Seq[F], List[T]] =
new Transformer[Seq[F], List[T]] {
override def transform(from: Seq[F]): List[T] = from.map(e.transform).toList
}
implicit final def transformerListSeq[F, T](implicit e: Transformer[F, T]): Transformer[List[F], Seq[T]] =
new Transformer[List[F], Seq[T]] {
override def transform(from: List[F]): Seq[T] = from.map(e.transform)
}
边栏推荐
- Failed to execute NPM instruction, prompting ssh: Permission denied
- [tcaplusdb knowledge base] Introduction to tcaplusdb tcapulogmgr tool (I)
- How to modify a node_ Files in modules
- Prometheus 2.26.0 new features
- OpenFeign服务接口调用
- 基于STM32设计的蓝牙健康管理设备
- [tcapulusdb knowledge base] Introduction to tcapulusdb tcapsvrmgr tool (III)
- hue新建账号报错解决方案
- Nifi from introduction to practice (nanny level tutorial) - identity authentication
- Deploy redis sentinel mode using bitnamiredis Sentinel
猜你喜欢

Size end byte order

ENSP cloud configuration

Record number of visits yesterday

深信服X计划-系统基础总结

AI for Science: scientific research paradigm, open source platform and industrial form

大小端字节序

Neo4j: basic introduction (I) installation and use

Teach you how to build a permanent personal server!

Explore tidb lightning source code to solve the found bugs

防火墙基础之华为华三防火墙web页面登录
随机推荐
【TcaplusDB知识库】TcaplusDB-tcapulogmgr工具介绍(一)
Cloud native (30) | kubernetes' app store Helm
Airbnb double disk microservice
Istio微服务治理网格流量管理核心资源控制器详解
Implementation of recruitment website based on SSM
每日刷題記錄 (六)
快讯:华为启动鸿蒙开发者大赛;腾讯会议发布“万室如意”计划
【医学分割】unet3+
Record number of visits yesterday
OpenFeign服务接口调用
Kotlin函数使用示例教程
#yyds干货盘点# 解决剑指offer:剪绳子(进阶版)
Convn-n dimensional convolution
zabbix支持钉钉报警
爱可可AI前沿推介(6.27)
不一样的习惯
Cesium实现卫星在轨绕行
清楚的自我定位
今日睡眠质量记录78分
How to open an account for CSI 500 stock index futures, what are the regular domestic stock index futures platforms, and where is the safest place to open an account?