Scala 类型参数不符合类型参数范围

Posted

技术标签:

【中文标题】Scala 类型参数不符合类型参数范围【英文标题】:Scala type arguments do not conform to type parameter bounds 【发布时间】:2021-01-19 09:23:04 【问题描述】:

我正在做一些我想概括的工作(一些行为在几个类中完全重复但针对不同的具体类型 [称为 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 有不同的实现(由代码生成),我试图用GeneralizationOverW 来概括W 使用不同的C

我尝试在 Scala 规范中阅读有关 compound types 的信息,但无法弄清楚为什么会出现以下编译错误以及如何修复它:

类型参数 [playground.Conformance.C1] 不符合 trait GeneralizationOverW 的类型参数界限 [C <: playground.conformance.rt w1 generalizationoverw>

已编辑:建议后更新代码:

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]




我认为它现在可以工作了:)

【问题讨论】:

【参考方案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]

【讨论】:

【参考方案2】:

发生了几件事:

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]


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

【讨论】:

我确实需要那些依赖于路径的类型,不是因为我实际使用它,而是因为这些特征已经有“客户”按原样使用它(RT 是 R 类型等事实)。 ..) - 所以我不能删除或更改除 GeneralizationOverW 和 W1、W2、W3 之外的任何内容。尝试了你建议的使它成为协方差的方法,现在我得到这是不可能的,因为路径相关的类型```协变类型 SD 出现在 ST 类型的 SD 覆盖类型 ST = SD ``` 的不变位置尝试做@TomerShetah 的事情,但似乎效果不佳。 用您的建议更新帖子并稍微扩展一下 别在意你的解释 + 我认为 tomer 的建议对我有用,谢谢你们的帮助!

以上是关于Scala 类型参数不符合类型参数范围的主要内容,如果未能解决你的问题,请参考以下文章

Scala隐式转换

大数据学习之Scala语言的高级特性42

15Scala隐式转换和隐式参数

Xitrum学习笔记12 - 范围

ADODB.Recordset 错误 '800a0bb9' 参数类型不正确,或不在可以接受的范围之内,或与其他参数冲突。

覆盖在Ada中接收类范围类型作为参数的过程