隐含对象转换的类型推断

时间:2014-07-01 09:25:52

标签: scala implicits

当前项目的一部分涉及从耦合到数据库的类型转换和通过Json将结果序列化到客户端时使用的泛型类型,Scala中的当前实现使用类型推断来正确执行转换,使用Scala' s 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)

这种方法虽然目前适用,但在添加可能更多的数据库类型时并不具备功能或可扩展性。我也觉得使用asInstanceOf应该是多余的,因为类型已被断言。我对implicits的有限知识表明它们可以用来代替执行转换,并且完全不需要上面的Transform[A: TypeTag](objects:Seq[A]):Seq[Children]方法。或者也许我应该使用不同的方法呢?

2 个答案:

答案 0 :(得分:1)

我不确定你的程序应该如何工作完全,也不知道你的任何变换是自制类型还是你从库中提取的东西,但是我无论如何可能有解决方案

match确实很好,case classes

因此,不是手动检查输入数据的类型,而是可以将它们全部包装在案例类中(如果您需要随身携带数据)或案例对象(如果您不是)

这样你可以这样做:

// 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)
}

通过将所有内容包装在案例类中,您可以准确指定要带入的数据类型,只要它们(案例类,而不是数据)都从相同的类/特征继承,就应该没事的

由于只有少数几个扩展ProductType的课程你不需要默认情况,因为 没有默认情况!

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

请注意,此解决方案要求您重新编写代码,因此在您投入代码之前请记住这一点。

答案 1 :(得分:1)

您可以定义如下特征:

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对象或与您的类别类对应的对象中定义隐式实例。