2011-07-31 48 views
13

考慮下面的Scala代碼:爲什麼Scala不能在類型參數嵌套時完全推斷類型參數?

abstract class A 
abstract class B[T <: A] 
class ConcreteA extends A 
class ConcreteB extends B[ConcreteA] 

class Example[U <: B[T], T <: A](resolver: U) 
object Test { 
    new Example(new ConcreteB) 
} 

最後一行new Example(new ConcreteB)失敗,出現以下錯誤編譯:

error: inferred type arguments [ConcreteB,Nothing] do not conform to class Example's type parameter bounds [U <: B[T],T <: A]

ConcreteB擁有所有解決雙方ü T.必要的數據我在這裏錯過了什麼?

+0

可能的重複[類型感染到斯卡拉Nothing](http://stackoverflow.com/questions/6888136/type-in​​fered-to-nothing-in-scala) –

+1

它是相似的,但接受的答案是問題不適用於這種情況。 –

回答

10

基普頓接近他的更高智慧的解決方案。不幸的是,他絆倒了似乎是Scala < 2.9.1.RC1中的一個bug。預期與2.9.1.RC1和軀幹以下的作品,

Welcome to Scala version 2.9.1.RC1 (Java HotSpot(TM) Server VM, Java 1.7.0). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> abstract class A 
defined class A 

scala> abstract class B[T <: A] 
defined class B 

scala> class ConcreteA extends A 
defined class ConcreteA 

scala> class ConcreteB[T <: A] extends B[T] 
defined class ConcreteB 

scala> class Example[T <: A, U[X <: A] <: B[X]](resolver: U[T]) 
defined class Example 

scala> new Example(new ConcreteB[ConcreteA]) 
res0: Example[ConcreteA,ConcreteB] = [email protected] 
+0

它很接近,但ConcreteB並不是真的具體。這是否適用於您而無需顯式參數化ConcreteB? –

+0

如果沒有'ConcreteB'的顯式參數化,我不能推理工作(但我首先提到的類型成員方法工作正常)。 –

+0

謝謝,我想這個時間點已經很接近了。 –

10

(另見兩個相關的問題:Scala fails to infer the right type argumentsType infered to Nothing in Scala

它看起來像Scala的類型推斷,這是不是故意的spec'ed限制。作爲變通,你可以通過T一個類型成員的B而非參數得到的推論,

abstract class A 
abstract class B { type T <: A } 
class ConcreteA extends A 
class ConcreteB extends B { type T = ConcreteA } 
class Example[U <: B](resolver: U) 
object Test { 
    new Example(new ConcreteB) 
} 

當使用類型成員,它是有用的知道,他們可以浮出水面使用細化類型的參數,如在萬里薩賓的回答如下:Why is this cyclic reference with a type projection illegal?

在Jean-Philippe Pellet對a related question的回答中,類型推斷是通過使類型參數更接近主題來幫助的。如果您ConcreteB引入額外的類型參數,然後鍵入推斷可以工作,

abstract class A 
abstract class B[T <: A] 
class ConcreteA extends A 
class ConcreteB[T <: A] extends B[T] 
class Example[T <: A, U[T0 <: A] <: B[T0]](resolver: U[T]) 
object Test { 
    new Example(new ConcreteB[ConcreteA]) 
} 

斯卡拉2.9給出了下面的神祕的錯誤消息,但萬里薩賓指出它是將固定爲2.9的bug。 1

<console>:15: error: kinds of the type arguments (ConcreteA,ConcreteB[T0]) do not conform to the expected kinds of the type parameters (type T,type U) in class Example. 
ConcreteB[T0]'s type parameters do not match type U's expected parameters: class ConcreteB has one type parameter, but type U has one 
     new Example(new ConcreteB[ConcreteA]) 
      ^
+1

請參閱下面關於Miles的回答的繼續討論。 –

+0

邁爾斯的答案現在已經成爲公認的答案。 – ArtB

2

我已經在GitHub上組成a document of type inference workarounds對我自己的學習。

,我覺得很有用一些簡單的規則是:

  • 的類型參數類型參數無法推斷: Scala的類型推斷只能看到在參數列表中指定類型(不要混淆與類型參數列表)。

  • 以前參數不用於推斷未來的參數:類型的信息只能隔着參數流列表,不參數


然而,在這個特殊的例子類型的成員是前進的方向(感謝@Kipton巴羅斯!)

相關問題