为什么我会收到 "type arguments...do not conform to trait..." 编译器错误?

Why am I getting an error of "type arguments...do not conform to trait..." compiler error?

我已经被 IntelliJ (14.1.5) 中的 Scala (2.11.7) 编译器错误卡住了好几个小时了。我在 Google 上搜索过,绞尽脑汁尝试了很多变体,但似乎无法绕过它。

我已经获取了代码上下​​文并将其剪裁得尽可能小(包括剪裁掉任何外部库依赖项)以捕获我一直用来尝试缩小问题范围的域。我以为我使用的是非常简单的惯用 Scala; case 对象、带有类型参数的 traits 等

最后一行以 abstract case class CoordinateRadian 开头的第四行是生成此 Scala 编译器错误的行:

Error:(128, 129) type arguments [Test.this.CoordinateRadian.unitBase.type,Test.this.LongitudeRadian,Test.this.LatitudeRadian] do not conform to trait Coordinate's type parameter bounds [U <: Test.this.Angle.UnitBase.Member,+O <: Test.this.Longitude[U],+A <: Test.this.Latitude[U]] abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, LongitudeRadian, LatitudeRadian] {

这是编译器错误的代码:

package org.public_domain

class Test {
  object Angle {
    object UnitBase {
      trait Member
      case object RADIAN extends Member
      case object DEGREE extends Member
    }
    trait UnitBase[U <: Angle.UnitBase.Member] {
      def unitBase: U
    }

    object ZeroBase {
      trait Member
      case object LEFT extends Member
      case object MIDDLE extends Member
    }
    trait ZeroBase[U <: Angle.UnitBase.Member, Z <: Angle.ZeroBase.Member] extends Angle.UnitBase[U] {
      def zeroBase: Z
    }
  }
  trait Angle[U <: Angle.UnitBase.Member, Z <: Angle.ZeroBase.Member] extends Angle.ZeroBase[U, Z] {
    def theta: Double
  }

  trait Angle__ObjectBase {
    def basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member)
  }

  object AngleRadianMiddle extends ((Double) => AngleRadianMiddle) with Angle__ObjectBase {
    val basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member) =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): AngleRadianMiddle =
      new AngleRadianMiddle(theta) {
        def unitBase =
          basesAsTuple._1

        def zeroBase =
          basesAsTuple._2

        private def readResolve(): Object =
          AngleRadianMiddle(theta)

        def copy(thetaNew: Double = theta): AngleRadianMiddle =
          AngleRadianMiddle(thetaNew)
      }
  }
  abstract case class AngleRadianMiddle private[AngleRadianMiddle] (theta: Double) extends Angle[AngleRadianMiddle.basesAsTuple._1.type, AngleRadianMiddle.basesAsTuple._2.type] {
    def copy(thetaNew: Double = theta): AngleRadianMiddle
  }

  trait Itude[U <: Angle.UnitBase.Member] extends Angle[U, Angle.ZeroBase.MIDDLE.type] {
    val zeroBase =
      Angle.ZeroBase.MIDDLE
  }

  sealed trait Longitude[U <: Angle.UnitBase.Member] extends Itude[U]
  sealed trait Latitude[U <: Angle.UnitBase.Member] extends Itude[U]

  object LongitudeRadian extends ((Double) => LongitudeRadian) {
    val basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member) =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): LongitudeRadian =
      new LongitudeRadian(theta) {
        def unitBase =
          basesAsTuple._1

        private def readResolve(): Object =
          LongitudeRadian(theta)

        def copy(thetaNew: Double = theta): LongitudeRadian =
          LongitudeRadian(thetaNew)
      }
  }
  abstract case class LongitudeRadian(theta: Double) extends Longitude[LongitudeRadian.basesAsTuple._1.type] {
    def copy(thetaNew: Double = theta): LongitudeRadian
  }

  object LatitudeRadian extends ((Double) => LatitudeRadian) {
    val basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member) =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): LatitudeRadian =
      new LatitudeRadian(theta) {
        def unitBase =
          basesAsTuple._1

        private def readResolve(): Object =
          LatitudeRadian(theta)

        def copy(thetaNew: Double = theta): LatitudeRadian =
          LatitudeRadian(thetaNew)
      }
  }
  abstract case class LatitudeRadian(theta: Double) extends Latitude[LatitudeRadian.basesAsTuple._1.type] {
    def copy(thetaNew: Double = theta): LatitudeRadian
  }

  trait Coordinate[U <: Angle.UnitBase.Member, +O <: Longitude[U], +A <: Latitude[U]] {
    def longitude: O
    def latitude: A

    val x: O =
      longitude
    val y: A =
      latitude
  }

  object CoordinateRadian extends ((LongitudeRadian, LatitudeRadian) => CoordinateRadian) {
    val unitBase: Angle.UnitBase.Member =
      Angle.UnitBase.RADIAN

    def apply(longitude: LongitudeRadian, latitude: LatitudeRadian): CoordinateRadian =
      new CoordinateRadian(longitude, latitude) {
        private def readResolve(): Object =
          CoordinateRadian(longitude, latitude)

        def copy(longitudeNew: LongitudeRadian = longitude, latitudeNew: LatitudeRadian = latitude): CoordinateRadian =
          CoordinateRadian(longitudeNew, latitudeNew)
      }
  }
  //abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, Longitude[CoordinateRadian.unitBase.type], Latitude[CoordinateRadian.unitBase.type]] {
  abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, LongitudeRadian, LatitudeRadian] {
    def copy(longitudeNew: LongitudeRadian = longitude, latitudeNew: LatitudeRadian = latitude): CoordinateRadian
  }
}

您会注意到文件末尾的第五行是注释掉的行(与文件末尾的第四行非常相似)。如果您取消注释最后一行的第五行,然后注释掉最后一行的第四行并编译代码(IntelliJ 中的 "Build All"),将发出两个错误:

Error:(125, 67) overriding method longitude in trait Coordinate of type => Test.this.Longitude[Test.this.CoordinateRadian.unitBase.type]; value longitude has incompatible type abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, Longitude[CoordinateRadian.unitBase.type], Latitude[CoordinateRadian.unitBase.type]] {

Error:(125, 95) overriding method latitude in trait Coordinate of type => Test.this.Latitude[Test.this.CoordinateRadian.unitBase.type]; value latitude has incompatible type abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, Longitude[CoordinateRadian.unitBase.type], Latitude[CoordinateRadian.unitBase.type]] {

我可能刚刚在这方面工作的时间太长了,现在眼睛有黄疸。一个多小时以来,我还没有想到任何新的方法来解决这个问题。所以,任何关于我做错了什么的指导将不胜感激。

嗯,根据 Coordinate 的限制,您需要 LongitudeRadian <: Longitude[CoordinateRadian.unitBase.type](纬度也类似),这是错误的,因为 LatitudeRadian.basesAsTuple._1.type 不是 [=15= 的子类型](编译器只知道 LatitudeRadian.basesAsTuple._1 是一个 Angle.UnitBase.Member)。如果你只是从 basesAsTupleunitBase 中删除类型注释,编译器 will infer the singleton types without problems.

class Test {
  object Angle {
    object UnitBase {
      trait Member
      case object RADIAN extends Member
      case object DEGREE extends Member
    }
    trait UnitBase[U <: Angle.UnitBase.Member] {
      def unitBase: U
    }

    object ZeroBase {
      trait Member
      case object LEFT extends Member
      case object MIDDLE extends Member
    }
    trait ZeroBase[U <: Angle.UnitBase.Member, Z <: Angle.ZeroBase.Member] extends Angle.UnitBase[U] {
      def zeroBase: Z
    }
  }
  trait Angle[U <: Angle.UnitBase.Member, Z <: Angle.ZeroBase.Member] extends Angle.ZeroBase[U, Z] {
    def theta: Double
  }

  trait Angle__ObjectBase {
    def basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member)
  }

  object AngleRadianMiddle extends ((Double) => AngleRadianMiddle) with Angle__ObjectBase {
    val basesAsTuple =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): AngleRadianMiddle =
      new AngleRadianMiddle(theta) {
        def unitBase =
          basesAsTuple._1

        def zeroBase =
          basesAsTuple._2

        private def readResolve(): Object =
          AngleRadianMiddle(theta)

        def copy(thetaNew: Double = theta): AngleRadianMiddle =
          AngleRadianMiddle(thetaNew)
      }
  }
  abstract case class AngleRadianMiddle private[AngleRadianMiddle] (theta: Double) extends Angle[AngleRadianMiddle.basesAsTuple._1.type, AngleRadianMiddle.basesAsTuple._2.type] {
    def copy(thetaNew: Double = theta): AngleRadianMiddle
  }

  trait Itude[U <: Angle.UnitBase.Member] extends Angle[U, Angle.ZeroBase.MIDDLE.type] {
    val zeroBase =
      Angle.ZeroBase.MIDDLE
  }

  sealed trait Longitude[U <: Angle.UnitBase.Member] extends Itude[U]
  sealed trait Latitude[U <: Angle.UnitBase.Member] extends Itude[U]

  object LongitudeRadian extends ((Double) => LongitudeRadian) {
    val basesAsTuple =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): LongitudeRadian =
      new LongitudeRadian(theta) {
        def unitBase =
          basesAsTuple._1

        private def readResolve(): Object =
          LongitudeRadian(theta)

        def copy(thetaNew: Double = theta): LongitudeRadian =
          LongitudeRadian(thetaNew)
      }
  }
  abstract case class LongitudeRadian(theta: Double) extends Longitude[LongitudeRadian.basesAsTuple._1.type] {
    def copy(thetaNew: Double = theta): LongitudeRadian
  }

  object LatitudeRadian extends ((Double) => LatitudeRadian) {
    val basesAsTuple =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): LatitudeRadian =
      new LatitudeRadian(theta) {
        def unitBase =
          basesAsTuple._1

        private def readResolve(): Object =
          LatitudeRadian(theta)

        def copy(thetaNew: Double = theta): LatitudeRadian =
          LatitudeRadian(thetaNew)
      }
  }
  abstract case class LatitudeRadian(theta: Double) extends Latitude[LatitudeRadian.basesAsTuple._1.type] {
    def copy(thetaNew: Double = theta): LatitudeRadian
  }

  trait Coordinate[U <: Angle.UnitBase.Member, +O <: Longitude[U], +A <: Latitude[U]] {
    def longitude: O
    def latitude: A

    val x: O =
      longitude
    val y: A =
      latitude
  }

  object CoordinateRadian extends ((LongitudeRadian, LatitudeRadian) => CoordinateRadian) {
    val unitBase =
      Angle.UnitBase.RADIAN

    def apply(longitude: LongitudeRadian, latitude: LatitudeRadian): CoordinateRadian =
      new CoordinateRadian(longitude, latitude) {
        private def readResolve(): Object =
          CoordinateRadian(longitude, latitude)

        def copy(longitudeNew: LongitudeRadian = longitude, latitudeNew: LatitudeRadian = latitude): CoordinateRadian =
          CoordinateRadian(longitudeNew, latitudeNew)
      }
  }
  //abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, Longitude[CoordinateRadian.unitBase.type], Latitude[CoordinateRadian.unitBase.type]] {

  abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, LongitudeRadian, LatitudeRadian] {
    def copy(longitudeNew: LongitudeRadian = longitude, latitudeNew: LatitudeRadian = latitude): CoordinateRadian
  }
}

但老实说,这对我来说似乎过度使用了单例类型。我根本不明白您为什么需要 unitBasebasesAsTuple。我更愿意写

abstract case class LongitudeRadian(theta: Double) extends Longitude[RADIAN.type]

abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[RADIAN.type, LongitudeRadian, LatitudeRadian]

等被无法证明两个对象相同的编译器咬住的机会要少得多。