在Scala 2.10中处理混合复杂Java泛型的集合



在我工作的公司,我们从(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](_) )

最新更新