Scala中的通用集合有问题

| 我对如何在Scala中解决此问题感到困惑。在Java中,我会放弃泛型或使用强制类型转换,但是Scala对此更为严格。这就是我所拥有的。 抽象基类“ 0”和此处无关的一些具体实现。这是协变的。此类具有创建Products的方法-请参阅下一点。 代表工厂产品的抽象基类
Product[+F <: Factory[F]]
。这些也是协变且只读的。任何特定的工厂都只生产一种类型的产品(即没有多个不同的子类型-FooFactory生产FooProduct,BarFactory生产BarProduct等) 我必须有一个包含具体实例的工厂集合(Capt。在这里很明显)。目前,这是
Iterable[Factory[_]]
。这是麻烦的第一部分。 Scala似乎将
_
理解为
Any
,而忽略了类型本身的约束
F <: Factory[F]
。 我有一个汇总工厂方法,要求每个工厂在给定相同参数的情况下生产其产品。结果是一张工厂到其产品的地图,当前编码为
Map[Factory[_],Product[_]]
,还尝试了
Map[Factory[_],Product[Factory[_]]]
。这是我遇到麻烦的另一部分。第一个
_
与第二个
_
是未链接的,并且两者都隐含为
Any
。 我不能做的就是创建该地图。它可能重要也可能不重要,但是我通过使用另一种看起来像语法构造的方法来做到这一点(必须这样做)。它来自一个特征,并且: 调用获取工厂集合的已声明方法(此处称为“ 11”,未在trait本身中实现且未使用通用类型)。实际的工厂类型是通用的并且是未知的。 遍历该通用集合并执行传递给它的函数。该函数实际上是所谓的工厂方法。 将F的不变
Map
返回给P 编译器的麻烦不在\'gather \'方法中,而在调用它的代码中。我无法将其结果强制转换为
Map[Factory[_],Product[_]]
,因为_在任何地方都不符合
F <: Factory[F]
...我很乐意为
_
使用基类型,但是那会是
Factory[Factory[Factory[Factory......(infinitely many times)]]]]]]....
,而我却不会\不知道该怎么办。 请帮忙! 学习者     
已邀请:
        在大多数情况下,除非您知道自己在做什么,否则在类型中使用
_
是错误的事情。而且,如果您不了解生存类型,那么您肯定不知道自己在做什么。 Scala并不是认为
_
Any
,而是知道
_
可以代表任何东西-
Any
Nothing
或介于两者之间的任何东西。 概括起来,
Iterable[Factory[_]]
表示
Iterable[Factory[T]] forSome { type T }
。您可以将其明确表示为
Iterable[Factory[T]] forSome { type T <: Factory[T] }
,以获得所需的约束,就像将其编写为
Map[Factory[T], Product[T]] forSome { type T <: Factory[T] }
一样。 不过,我不确定您是否真的需要。您的问题集中在如何解决问题上,而不是集中在解决问题上。例如,可能最好使用以下内容代替泛型:
abstract class Factory {
    type T <: Factory
}
    
如果我的Scala有点生锈,请原谅我。我写的是一般OOP和泛型的意思。 目前尚不清楚为什么
Factory
Product
根本需要泛型,而使协方差大为混乱。无论是否实际需要,都有一个简单的非泛型类
FactoryBase
是必要的且足够的,最终所有
Factory
类都将继承。你把它塞进
Iterable[FactoryBase]
。 还不清楚为什么“ 29”类型包含有关“ 28”的任何信息。如果您确实需要相反的信息,则相反。
Factory
产生a29ѭ,因此知道它,因此该知识可能会反映在类型中。再说一次,可能不会。 万一您需要通用性,协方差和完整类型信息,则可以使用以下层次结构:
FactoryBase
   Factory[+F <: Factory[F,P], +P <: Product[F,P]] <: FactoryBase
      FooFactory <: Factory[FooFactory, FooProduct]
ProductBase
   Product[+F <: Factory[F,P], +P <: Product[F,P]] <: ProductBase
      FooProduct <: Product[FooFactory, FooProduct]
可以随意省略不需要的任何类型参数。 还不清楚为什么需要一个将工厂映射到产品的地图。地图通常将名称之类的东西映射到实体。也就是说,给定名称,找到具有该名称的现有实体。工厂凭空创造新事物。无论如何,如果您确实需要这样的地图,可以使用
Map[FactoryBase, ProductBase]
。这不能提供静态保证that39ѭ映射到
FooProduct
而不是
BarProduct
,但是
Map
不能提供。再说一次,您只需将ѭ29stick插入其相应的
Factory
中即可。您已经知道编译时的映射,不需要运行时
Map
。第四十六条,产品生产后无需与任何工厂关联。 也许我完全误解了您,您需要在设计上进行很多阐述。因此,它的目的和体系结构还不清楚。     
        我不太确定我能理解您的问题,但是请尝试使用类似以下内容的方法:
gather[A : Factory, B : Factory](fun: A => B): Map[A,B]
    
添加另一个答案,而不是编辑旧答案。 我将不必就Scala类型系统进行讨论,因为此处的思想适用于许多不同的语言。 首先,在讨论地图之前,让我展示如何制作更深的并行层次结构。这真的很简单,只需插入另一个级别:
FactoryBase
   Factory[+F <: Factory[F,P], +P <: Product[F,P]] <: FactoryBase
      SomeFactoryGroup[+F <: SomeFactoryGroup[F,P], +P <: SomeProductGroup[F,P]] <: Factory[SomeFactoryGroup, SomeProductGroup]
        FooFactory <: SomeFactoryGroup[FooFactory, FooProduct]
ProductBase
   Product[+F <: Factory[F,P], +P <: Product[F,P]] <: ProductBase
      SomeFactoryGroup[+F <: SomeFactoryGroup[F,P], +P <: SomeProductGroup[F,P]] <: Product[SomeFactoryGroup, SomeProductGroup]
        FooProduct <: SomeProductGroup[FooFactory, FooProduct]
您可以插入任意多个级别。我们需要所有这些,包括非通用的
FactoryBase
ProductBase
。尽管它们并不是严格必需的,因为可以摆脱存在性类型,但是它们可能很笨拙。
FactoryBase
(SomeFactory | exist F <: Factory[F,P], exist P <: Product[F,P], SomeFactory <: F)
更容易说出来(故意不是Scala语法)。有时,存在性非常有用,但是在此示例中却没有(也许您可以在系统的其他部分中使用它们)。无论如何,这些“ 30”个对象将被放置在“ 32”中以管理生产运行。 现在到地图。在生产过程中,每个工厂可能会生产一个产品实例(或可能没有)。给定工厂和生产运行,我们需要找到该工厂在运行期间生产的产品。 一种解决方案是您尝试过的解决方案:将生产运行表示为(或包含或从工厂到产品的映射)。暂时忽略类型,使用伪代码:
productionrun.lookup(factory) = productionrun.mapFromFactoryToProduct.lookup(factory)
如果我们坚持
FactoryBase
ProductBase
,这甚至可以工作。但是这种方法是有限的。映射将一堆类型为A的事物映射为一堆(可能不同)类型为B的事物。所有键都是相同类型的,而所有值都是相同类型的。这显然不是我们所拥有的。所有工厂的类型不同,所有产品也是如此。我们可以通过忘记部分类型信息来解决此问题,也就是说,通过存储简化为最小公分母类型的键和值。但是,如果以后需要恢复此类信息怎么办?这不可能静态地完成,它被遗忘,永远丢失。 另一种解决方案与第一个解决方案表面上对称:让工厂代表(或包含,在这种情况下)从生产运行到产品的地图。
factory.lookup(productionrun) = factory.mapFromProductionRunToProduct.lookup(productionrun)
在这种情况下,生产运行仅由其唯一ID表示。但是在类型级别上,此解决方案与第一个解决方案完全不同,并且要好得多。每个映射中的所有键都是相同类型的(实际上,它们在不同工厂中都是相同类型的)。每个映射中的所有值都是类型相同的(此类型特定于工厂)。在任何阶段都不会丢失类型信息。 因此,总结一下。
PR
代表生产运行。创建方法“ 60”,并通过“ 61”实现。使用
makeProduct
方法接受
PR
值,然后将结果乘以
PR
值添加到地图中。您可以将其包装为方法
PR.lookUpProductByFactory[F,P](f:Factory[F,P])->Product[F,P]
或其他类似方法。另外,将其包裹在
FactoryBase.findProduct(pr:PR)->ProductBase
中,然后将其包裹在
PR.lookUpProductBaseByFactoryBase(f:FactoryBase)->ProductBase
中。 而已。我希望这两种解决方案都能满足您的需求。     

要回复问题请先登录注册