在我工作的公司,我们从(Java)模式中获得了很多好处,可以总结如下:
有些"东西"我们可以通过它们的特殊/智能"id"得到。每个"东西"都有它的id, id是"聪明的",因为你可以让它们给你它们识别的"东西"。在复杂的不断增长的"事物"层次结构中,这简化了维护并消除了大量代码(重复和其他)。我相信你们中的一些人可能会觉得这很奇怪,我可以解释一下为什么会这样,但事实是它是这样的,到目前为止它是有帮助的,不是问题的一部分。
Java定义的摘要如下(稍作重写):
interface Id<I extends Id<I,T>, T extends Thing<I,T>> {
T getThing();
...
}
interface Thing<I extends Id<I,T>, T extends Thing<I,T>> {
public I getId();
...
}
有时,我们需要获得给定一批不同id的"批处理"(这是跨网络的,因此批处理可以加快速度)。为了便于描述,它可以写成:
public Map<Id<?,?>,Thing<?,?>> getManyThings(List<Id<?,?>> idsToGetThingsFor);
(方法参数是一个简单的id的复数,不管它是一个集合,列表或其他)
现在,在网络的另一端,这个方法在Scala 2.9中实现了,相当难看地避免了Scala泛型的严格性。我们正在尝试升级到Scala 2.10,但是已经无法编译了,我们必须想办法解决这个问题。诀窍是有一个Scala方法总结如下:
def getOneThing[I <: Id[I,T],T <: Thing[I,T]](id: I): T;
该方法根据许多因素适当地检查、处理和分配调用——这里解释太多了,而且不相关。
现在,它是getManyThings()方法,迭代传递给它的id,并需要将它们作为参数传递给getOneThing()。这就是事情失败的地方。getManyThings()只知道它获取的Id本质上是Id[,], Scala抱怨[,]对于[I <: Id[I,T],T <: Thing[I,T]]来说不够好,而getOneThing()需要:
... error: inferred type arguments [Id[_$16,_$17],Nothing] do not conform to method getOneThing's type parameter bounds [I <: Id[I,T],T <: Thing[I,T]]
注意-为Id和Thing声明非参数化(非泛型)基类并没有真正的帮助,因为它只会把问题推到(太多)其他地方。我们选择非常严格的类型来确保代码质量,但我们必须有一种方法来处理"混合"集合。
帮忙吗?拜托!
我假设您有这样一个方法:
def getManyThings[I <: Id[I, T], T <: Thing[I, T]](ids:List[I]):List[T] =
ids map getOneThing
这将给出一个错误,因为编译器不能推断出你想调用getOneThing
方法,T
作为第二个类型参数。
为了"帮助"编译器,你需要显式地传递它们:
trait Id[I <: Id[I, T], T <: Thing[I, T]]
trait Thing[I <: Id[I, T], T <: Thing[I, T]]
def getOneThing[I <: Id[I, T], T <: Thing[I, T]](id:I):T = ???
def getManyThings[I <: Id[I, T], T <: Thing[I, T]](ids:List[I]):List[T] =
ids map ( getOneThing[I, T](_) )