当前位置:网站首页>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)
}
边栏推荐
- Threejs' ambient light + point light + parallel light + spherical light and Hepler understanding + shadow ()
- ThreadLocal 源码全详解(ThreadLocalMap)
- Shell 简明教程
- jvm 性能调优、监控工具 -- jps、jstack、jmap、jhat、jstat、hprof
- Airbnb double disk microservice
- ZABBIX supports nail alarm
- 不一样的习惯
- 嵌入式开发:嵌入式基础——回调函数
- 让学指针变得更简单(一)
- 每日刷题记录 (六)
猜你喜欢

【TcaplusDB知识库】TcaplusDB-tcapsvrmgr工具介绍(三)

Details of istio micro service governance grid traffic management core resource controller

Crane: a new way of dealing with dictionary items and associated data

每日刷题记录 (六)

Cesium实现卫星在轨绕行

这是什么空调?

ENSP cloud configuration

Quick news: Huawei launched the Hongmeng developer competition; Tencent conference released the "Wanshi Ruyi" plan

夏日里的清凉
![[acwing] explanation of the 57th weekly competition](/img/ef/be89606b0e7fffac08280db0a73781.gif)
[acwing] explanation of the 57th weekly competition
随机推荐
Full explanation of ThreadLocal source code (threadlocalmap)
jvm 参数设置与分析
nifi从入门到实战(保姆级教程)——身份认证
Deploy redis sentinel mode using bitnamiredis Sentinel
#yyds干货盘点# 解决剑指offer:剪绳子(进阶版)
Pre training weekly issue 51: reconstruction pre training, zero sample automatic fine tuning, one click call opt
快速搭建一个自己的访问国外网站,搭建ss并开启bbr快速上网
POSIX AIO -- glibc 版本异步 IO 简介
面试官:Redis的共享对象池了解吗?
每日刷题记录 (六)
ThreadLocal 源码全详解(ThreadLocalMap)
Socket blocking and non blocking modes
数字化新星何为低代码?何为无代码
使用bitnamiredis-sentinel部署Redis 哨兵模式
万物互联时代到来,锐捷发布场景化无线零漫游方案
Bluetooth health management device based on stm32
Istio微服务治理网格流量管理核心资源控制器详解
scrapy
不一样的习惯
Ali an interview question: use two threads to output letters and numbers alternately