0

我正在做一些我想概括的工作(一些行为在几个类中完全重复,但对于不同的具体类型 [称为 C,见下文]),为了能够使用所有具体类型之间共有的那些接口的一些行为(听起来非常抽象和笼统......解释我的问题的最佳方法是查看代码)。

我用类似的结构简化了真实的代码,只是为了演示这个问题

package playground

object Conformance {
  trait S
  trait G
  trait R {
    type ST <: S
    type GT <: G

    def getS: ST
    def getG: GT
  }
  trait RT[SD <: S, GD <: G] extends R {
    override type ST = SD
    override type GT = GD
  }
  
  final case class ConcreteS() extends S

  final case class ConcreteG() extends G

  final class C1 extends RT[ConcreteS, ConcreteG] {
    override def getS: ConcreteS = ConcreteS()

    override def getG: ConcreteG = ConcreteG()
  }
  //some different impl
  final class C2 extends RT[ConcreteS, ConcreteG]{
    override def getS: ConcreteS = ConcreteS()

    override def getG: ConcreteG = ConcreteG()
  }
  //some different impl
  final class C3 extends RT[ConcreteS, ConcreteG]{
    override def getS: ConcreteS = ConcreteS()

    override def getG: ConcreteG = ConcreteG()
  }

  //generic impl over W
  trait GeneralizationOverW[C <: RT[S, G]] {
   // With `<: RT[S, G]` restriction I know C is RT with some S and G I can use S and G behaviours
  }
  
  class W1 extends GeneralizationOverW[C1]
  class W2 extends GeneralizationOverW[C2]
  class W3 extends GeneralizationOverW[C3]

}


想象一下C1,C2,C3有不同的实现(由代码生成),我试图用不同的 C 来概括 WGeneralizationOverW

我试图阅读Scala 规范中的复合类型,但无法弄清楚为什么会出现以下编译错误以及如何修复它:

类型参数 [playground.Conformance.C1] 不符合特征 GeneralizationOverW 的类型参数边界 [C <: playground.Conformance.RT[playground.Conformance.S,playground.Conformance.G]] 类 W1 扩展 GeneralizationOverW[C1]

编辑:建议后更新代码:

package playground

object Conformance {
  trait S
  trait SS extends S
  trait G
  trait R {
    type ST <: S
    type GT <: G

    def getS: ST
    def getG: GT
  }
  trait RT[SD <: S, GD <: G] extends R {
    override type ST = SD
    override type GT = GD
  }

  final case class ConcreteS1() extends SS
  final case class ConcreteS2() extends SS
  final case class ConcreteS3() extends SS

  final case class ConcreteG1() extends G
  final case class ConcreteG2() extends G
  final case class ConcreteG3() extends G

  final class C1 extends RT[ConcreteS1, ConcreteG1] {
    override def getS: ConcreteS1 = ConcreteS1()

    override def getG: ConcreteG1 = ConcreteG1()
  }
  //some different impl
  final class C2 extends RT[ConcreteS2, ConcreteG2]{
    override def getS: ConcreteS2 = ConcreteS2()

    override def getG: ConcreteG2 = ConcreteG2()
  }
  //some different impl
  final class C3 extends RT[ConcreteS3, ConcreteG3]{
    override def getS: ConcreteS3 = ConcreteS3()

    override def getG: ConcreteG3 = ConcreteG3()
  }

  //generic impl over W
  trait GeneralizationOverW[ST <: S,GT <: G , CON <: RT[ST, GT]] {
    //  With `<: RT[S, G]` restriction I know C is RT with some S and G I can use S and G behaviours
  }

  class W1 extends GeneralizationOverW[ConcreteS1,ConcreteG1,C1]
  class W2 extends GeneralizationOverW[ConcreteS2,ConcreteG2,C2]
  class W3 extends GeneralizationOverW[ConcreteS3,ConcreteG3,C3]


}

我认为它现在有效:)

4

2 回答 2

1

我不确定这是您正在寻找的,但您可以尝试:

trait GeneralizationOverW[S1 <: S, G1 <: G, C <: RT[S1, G1]] {
  // With `<: RT[S, G]` restriction I know C is RT with some S and G I can use S and G behaviours
}

class W1 extends GeneralizationOverW[ConcreteS, ConcreteG, C1]
class W2 extends GeneralizationOverW[ConcreteS, ConcreteG, C2]
class W3 extends GeneralizationOverW[ConcreteS, ConcreteG, C3]
于 2021-01-19T10:09:58.067 回答
1

有几件事正在发生:

trait GeneralizationOverW[C <: RT[S, G]] {

}

它期望C在这里传递的将RT[S, G]完全扩展,使用SG不是它的子类型,因为RT在两个参数中都是不变的。

您可以通过添加使其成为协变的+

trait RT[+SD <: S, +GD <: G] {
  def getS: SD
  def getG: GD
}

我删除了extends R因为路径相关类型STGT在此处定义:

trait R {
  type ST <: S
  type GT <: G

  def getS: ST
  def getG: GT
}

是不变的,不能成为协变的。如果您放弃使用R(您的示例根本没有使用路径相关类型),您可以创建一个有效的代码:

object Conformance {
  trait S
  trait G

  trait RT[+SD <: S, +GD <: G] {
    def getS: SD
    def getG: GD
  }

  final case class ConcreteS() extends S

  final case class ConcreteG() extends G

  final class C1 extends RT[ConcreteS, ConcreteG] {
    override def getS: ConcreteS = ConcreteS()

    override def getG: ConcreteG = ConcreteG()
  }
  //some different impl
  final class C2 extends RT[ConcreteS, ConcreteG]{
    override def getS: ConcreteS = ConcreteS()

    override def getG: ConcreteG = ConcreteG()
  }
  //some different impl
  final class C3 extends RT[ConcreteS, ConcreteG]{
    override def getS: ConcreteS = ConcreteS()

    override def getG: ConcreteG = ConcreteG()
  }

  //generic impl over W
  trait GeneralizationOverW[C <: RT[S, G]] {
   // With `<: RT[S, G]` restriction I know C is RT with some S and G I can use S and G behaviours
  }

  class W1 extends GeneralizationOverW[C1]
  class W2 extends GeneralizationOverW[C2]
  class W3 extends GeneralizationOverW[C3]

}

但是,如果您确实需要这些依赖于路径的类型,则应使用 @TomerShetah 答案中的硬编码S和绑定参数替换。G

于 2021-01-19T10:19:48.540 回答