2015-10-07 28 views
1

我一直卡在IntelliJ(14.1.5)的Scala(2.11.7)編譯器錯誤現在幾個小時。我已經谷歌搜索,扼殺了我的大腦,並嘗試了大量的變化,但似乎無法繞過它。爲什麼我會收到「類型參數...不符合特性......」編譯器錯誤的錯誤?

我已經採取了代碼上下​​文,並儘可能小地剪裁它(包括刪除任何外部庫依賴項)以捕獲我一直用來嘗試縮小問題的域。我以爲我使用的是非常直接的慣用Scala;情況下的物體,與類型參數性狀等

從開始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),兩個錯誤會發出:

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]] {

我可能只是工作在這太久了,現在有一個黃疸的眼睛。我還沒有想到在一個多小時內有任何新的方法來解決這個問題。所以,對於我做錯什麼的指導將不勝感激。

回答

1

好了,通過在Coordinate約束,你需要有LongitudeRadian <: Longitude[CoordinateRadian.unitBase.type](以及類似緯度),這是錯誤的,因爲LatitudeRadian.basesAsTuple._1.type不是CoordinateRadian.unitBase.type亞型(編譯器知道只有LatitudeRadian.basesAsTuple._1Angle.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] 

等等被編譯器咬住無法證明兩個對象的機會是相同的。

+0

太棒了! Tysvm!我非常感謝你的回答。當然,它會引發下一個問題......爲什麼我在這些聲明中重複完全相同的類型信息(如果標識是身份...)會導致編譯器變得困惑?我遇到了很多編譯器問題的另一個方向(錯誤地推斷類型),我贊成在默認情況下指定類型。現在即使過度指定(以身份爲基礎)也會導致編譯器問題,這是相當令人沮喪的。 – chaotic3quilibrium

+0

你是如何在冥府中找到答案的?是什麼讓你認爲去基地AsTuple和unitBase的類型超標?我只是試圖通過我將來如何爲自己做同樣的事情。你是否有一些額外的工具,你正在使用的表面更多的是什麼編譯器正在做什麼,它是困惑,導致你這些特定的聲明?這不是我曾經考慮過的路線(根據我的身份假設)。 – chaotic3quilibrium

+0

正如我所說的,只要查看「座標」的約束條件和「CoordinateRadian」和「LatitudeRadian」的類型參數就可以清楚地說明問題。您不是「重複相同的信息」:編譯器推斷例如'val basesAsTuple:(Angle.UnitBase.RADIAN.type,Angle.ZeroBase.MIDDLE。類型)'在'LatitudeRadian'中,_not_'val basesAsTuple:(Angle.UnitBase.Member,Angle.ZeroBase.Member)'。所以它知道'LatitudeRadian.basesAsTuple._1'是'Angle.UnitBase.RADIAN'和'LatitudeRadian.basesAsTuple._1.type'與'Angle.UnitBase.RADIAN.type'是相同的,這就是約束所要求的。 –

相關問題