当前位置:网站首页>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)
}
边栏推荐
- Yuweng information, a well-known information security manufacturer, joined the dragon lizard community to build an open source ecosystem
- Configuration management center of microservices
- Clear self orientation
- 手把手教你搭一个永久运行的个人服务器!
- 昨天访问量破记录
- 不一样的习惯
- Hardware development notes (VII): basic process of hardware development, making a USB to RS232 module (VI): creating 0603 package and associating principle graphic devices
- A pang's operation record
- Using FRP tool to realize intranet penetration
- Local visualization tool connects to redis of Alibaba cloud CentOS server
猜你喜欢
随机推荐
Deploy redis sentinel mode using bitnamiredis Sentinel
再懂已是曲中人
局域网即时通讯软件应该怎么选择
【动态规划】—— 背包问题
Record number of visits yesterday
mysql 锁机制与四种隔离级别
[tcaplusdb knowledge base] Introduction to tcaplusdb tcapulogmgr tool (I)
基于STM32设计的蓝牙健康管理设备
Summary of redis master-slave replication principle
L June training (day 27) - figure
【TcaplusDB知识库】TcaplusDB-tcapsvrmgr工具介绍(三)
Local visualization tool connects to redis of Alibaba cloud CentOS server
不一样的习惯
Size end byte order
深信服X计划-系统基础总结
How to set postman to Chinese? (Chinese)
这是什么空调?
Intranet learning notes (8)
awk 简明教程
socket阻塞和非阻塞模式









