当前位置:网站首页>如何使用200行代码实现Scala的对象转换器

如何使用200行代码实现Scala的对象转换器

2022-06-27 12:58:00 梦境迷离

与CSV转换器类似,但本次所需要处理的类型是不可预见的,所以实现略有不同。

API 定义

trait Transformer[-From, +To] {
    
  def transform(from: From): To
}

object Transformer {
    
  def apply[From, To](implicit st: Transformer[From, To]): Transformer[From, To] = st
}

创建Transformer实例

有API后就是实现API,这可以通过两种方式来实现:

  1. 使用macro生成。
  2. 自己new一个。

下面只介绍用宏生成的方式。

使用macro生成

定义宏DSL

object Transformable {
    

  def apply[From <: Product, To <: Product]: Transformable[From, To] =
    macro TransformerMacro.applyImpl[From, To]
}

提供setNamesetType两个方法,分别提供对字段的名称和类型做编译期映射:

/** @author * 梦境迷离 * @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]

}

这么用:

    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)"

原理

  1. 编译期间存储setNamesetType的映射关系,并在类型不兼容时调用映射函数。
  2. 利用implicit,根据需要,会自动搜索并应用符合要求的Transformer隐式值。
  3. setType不是必须的,因为默认搜索implicit Transformer[From, To],如果没有才需要使用setType,但是如果已经定义了implicit Transformer[From, To],则不需要,不过setType的优先级更高,会覆盖implicit。

超复杂结构:

    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 {
    
      // 定义了就不需要在下面使用setType方法了
      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)))"

这是因为默认提供了常见集合,所以用户端不需要定义这些集合的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)
    }
原网站

版权声明
本文为[梦境迷离]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_34446485/article/details/125386330