当前位置:网站首页>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)
}
边栏推荐
- How to choose LAN instant messaging software
- Istio微服务治理网格流量管理核心资源控制器详解
- 抖音实战~公开/私密短视频互转
- 微服务如何拆分
- 使用bitnamiredis-sentinel部署Redis 哨兵模式
- 如何使用200行代码实现Scala的对象转换器
- ZABBIX supports nail alarm
- [tcaplusdb knowledge base] Introduction to tcaplusdb tcapulogmgr tool (I)
- Centos7 command line installation Oracle11g
- Two TCP flow control problems
猜你喜欢

Ali an interview question: use two threads to output letters and numbers alternately

Summary of redis master-slave replication principle

Pycharm in Chinese

Principle of printf indefinite length parameter

After 2 years of outsourcing, I finally landed! Record my ByteDance 3 rounds of interviews, hope to help you!

C语言 函数指针与回调函数

《预训练周刊》第51期:重构预训练、零样本自动微调、一键调用OPT

Explore tidb lightning source code to solve the found bugs

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

万物互联时代到来,锐捷发布场景化无线零漫游方案
随机推荐
Embedded development: embedded foundation callback function
How to set postman to Chinese? (Chinese)
Record number of visits yesterday
Differences in perspectives of thinking
zabbix支持钉钉报警
Infiltration learning diary day20
L June training (day 27) - figure
Istio微服务治理网格流量管理核心资源控制器详解
Bluetooth health management device based on stm32
Details of istio micro service governance grid traffic management core resource controller
Make learning pointer easier (1)
基于SSM实现招聘网站
云原生(三十) | Kubernetes篇之应用商店-Helm
今天运气不错
Ali an interview question: use two threads to output letters and numbers alternately
Prometheus 2.26.0 new features
Postman如何设置成中文?(汉化)
隐私计算FATE-离线预测
JSON.stringify用法
Full explanation of ThreadLocal source code (threadlocalmap)