Scala可以根据调用者实际预期的返回类型推断出实际类型吗?

时间:2016-11-25 10:40:42

标签: scala

我有一个问题。我们的项目有很多代码,在Scala中运行测试。并且有很多代码填充了这样的字段:

production.setProduct(new Product)
production.getProduct.setUuid("b1253a77-0585-291f-57a4-53319e897866")
production.setSubProduct(new SubProduct)
production.getSubProduct.setUuid("89a877fa-ddb3-3009-bb24-735ba9f7281c")

最终,我厌倦了这段代码,因为所有这些字段实际上都是具有uuid字段的基类的子类,所以,经过一段时间的思考,我写了这样的辅助函数:

def createUuid[T <: GenericEntity](uuid: String)(implicit m : Manifest[T]) : T = {
    val constructor = m.runtimeClass.getConstructors()(0)
    val instance = constructor.newInstance().asInstanceOf[T]
    instance.setUuid(uuid)
    instance
}

现在,我的代码缩短了两倍,因为现在我可以写这样的东西:

production.setProduct(createUuid[Product]("b1253a77-0585-291f-57a4-53319e897866"))
production.setSubProduct(createUuid[SubProduct]("89a877fa-ddb3-3009-bb24-735ba9f7281c"))

这很好,但我想知道,如果我能以某种方式实现createUuid函数,那么最后一点是这样的:

// Is that really possible?
production.setProduct(createUuid("b1253a77-0585-291f-57a4-53319e897866"))
production.setSubProduct(createUuid("89a877fa-ddb3-3009-bb24-735ba9f7281c"))

scala编译器可以猜测,setProduct不仅要求通用实体,而且实际上是Product(或它的子类)吗?或者Scala没有办法实现这个更短的时间?

1 个答案:

答案 0 :(得分:1)

Scala编译器不会推断/传播 out-in 类型。但是,您可以创建隐式转换,如:

implicit def stringToSubProduct(uuid: String): SubProduct = { 
  val n = new SubProduct
  n.setUuid(uuid)
  n
}

然后只需致电

production.setSubProduct("89a877fa-ddb3-3009-bb24-735ba9f7281c")

并且编译器将自动使用stringToSubProduct,因为它在输入和输出上具有适用的类型。

更新:为了让代码更有条理,我建议将implicit def包装到随播对象,例如:

case class EntityUUID(uuid: String) {
  uuid.matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") // possible uuid format check
}
case object EntityUUID {

  implicit def toProduct(e: EntityUUID): Product = {
    val p = new Product
    p.setUuid(e.uuid)
    p
  }

  implicit def toSubProduct(e: EntityUUID): SubProduct = {
    val p = new SubProduct
    p.setUuid(e.uuid)
    p
  }
}

然后你会做

production.setProduct(EntityUUID("b1253a77-0585-291f-57a4-53319e897866"))

所以读这篇文章的人都可以直截了当地找到转换实现。

关于你对一些通用方法的评论(有30种类型),我不会说这是不可能的,但我只是看不出怎么做。您使用的反射会绕过类型系统。如果所有30个案例都是同一段代码,那么您可能应该重新考虑您的对象设计。现在,您仍然可以通过调用一些使用与您提供的类似的反射的方法来实现30 implicit def。但是你可以选择在将来这一(30)个地方改变它。