我有一个问题。我们的项目有很多代码,在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没有办法实现这个更短的时间?
答案 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)个地方改变它。