Scala 对象转换的隐式类型推理

Scala 对象转换的隐式类型推理,scala,implicits,Scala,Implicits,当前项目的一部分涉及从耦合到数据库的类型和通过Json将结果序列化到客户端时使用的泛型类型转换,Scala中的当前实现使用类型推断来正确执行转换,使用Scala的TypeTag: def Transform[A: TypeTag](objects:Seq[A]):Seq[Children] = typeOf[A] match { case pc if pc =:= typeOf[ProductCategory] => TransformProductCategory(objec

当前项目的一部分涉及从耦合到数据库的类型和通过Json将结果序列化到客户端时使用的泛型类型转换,Scala中的当前实现使用类型推断来正确执行转换,使用Scala的TypeTag:

def Transform[A: TypeTag](objects:Seq[A]):Seq[Children] = typeOf[A] match {
  case pc if pc =:= typeOf[ProductCategory] =>
    TransformProductCategory(objects.asInstanceOf[Seq[ProductCategory]])

  case pa if pa =:= typeOf[ProductArea] => 
    TransformProductArea(objects.asInstanceOf[Seq[ProductArea]])

  case pg if pg =:= typeOf[ProductGroup] =>
    TransformProductGroup(objects.asInstanceOf[Seq[ProductGroup]])

  case psg if psg =:= typeOf[ProductSubGroup]  =>
    TransformProductSubGroup(objects.asInstanceOf[Seq[ProductSubGroup]])

  case _ => 
    throw new IllegalArgumentException("Invalid transformation")
}
用作输入的类型都是案例类,在应用程序内部定义,例如:

case class ProductCategory(id: Long, name: String, 
                           thumbnail: Option[String], 
                           image:Option[String], 
                           sequence:Int)

这种方法虽然目前适用,但在可能添加更多的DB类型时感觉不到功能性或可伸缩性。我还觉得使用
asInstanceOf
应该是多余的,因为类型已经被断言了。我对隐式的有限了解表明,可以使用隐式来执行转换,并且完全不需要上述
转换[A:TypeTag](objects:Seq[A]):Seq[Children]
方法。或者也许我应该用另一种方法来代替

我不确定你的程序到底应该如何工作,也不知道你的任何转换是自制类型还是从库中提取的东西,不过我可能有一个解决方案

一些
匹配
非常好用的东西是
案例类

所以,不必手动检查输入数据的类型,您可以将它们全部包装在case类(如果您需要携带数据)或case对象(如果您不需要)中

这样,您可以执行以下操作:

// this code assumes ProductCategory, ProductArea, etc. 
// all extends the trait ProductType
def Transform(pType: ProductType): Seq[Children] = pType match {
  case ProductCategory(objects)  => TransformProductCategory(objects)
  case ProductArea(objects)      => TransformProductArea(objects)
  case ProductGroup(objects)     => TransformProductGroup(objects)
  case ProductSubGroup(objects)  => TransformProductSubGroup(objects)
}
trait Transformer[A] {
  def transformImpl(x: Seq[A]): Seq[Children]
}
通过将所有内容包装在一个case类中,您可以精确地指定要携带的数据类型,只要它们(case类,而不是数据)都继承自同一个类/特征,就可以了

由于只有少数几个类扩展了
ProductType
,所以不需要默认情况,因为没有默认情况

另一个好处是,它可以无限扩展;只需添加更多案例和案例类


请注意,此解决方案需要您对代码进行大量重构,因此在投入其中之前,请牢记这一点。

您可以定义如下特征:

// this code assumes ProductCategory, ProductArea, etc. 
// all extends the trait ProductType
def Transform(pType: ProductType): Seq[Children] = pType match {
  case ProductCategory(objects)  => TransformProductCategory(objects)
  case ProductArea(objects)      => TransformProductArea(objects)
  case ProductGroup(objects)     => TransformProductGroup(objects)
  case ProductSubGroup(objects)  => TransformProductSubGroup(objects)
}
trait Transformer[A] {
  def transformImpl(x: Seq[A]): Seq[Children]
}
然后可以定义一些实例:

object Transformer {
  implicit val forProduct = new Transformer[ProductCategory] {
     def transformImpl(x: Seq[ProductCategory]) = ...
  }
  ...
}
最后:

def transform[A: Transformer](objects:Seq[A]): Seq[Children] = 
   implicitly[Transformer[A]].transformImpl(objects)

最好是在
Transformer
对象或与您的类别类对应的对象中定义隐式实例。

我不明白为什么人们更喜欢
def transform[A:Transformer](对象:Seq[A]):Seq[Children]=隐式[Transformer[A].
def transform[A]之上的transformImpl(对象)
(对象:Seq[A])(隐式t:Transformer[A])=t.transformImpl(对象)
。。。从长远来看,不断被迫隐式地使用
[]
肯定会变得非常陈旧,所以为什么不让Scala自动执行呢?