2009-07-26 118 views
8

假設我有兩個類,InputOutput,它們被設計爲相互連接。 Output產生某種類型的值,並且Input消耗它們。爲什麼在這個例子中Scala不能推斷出類型參數?

class Input[T] { 
    var output: Option[Output[_ <: T]] = None 
} 
class Output[T] { 
    var input: Option[Input[_ >: T]] = None 
} 

如果InputOutput對不上相同類型的值只要Input類型參數是Output類型參數的超類型操作沒事。請注意,兩個類中的類型參數都是不變的;在真正的版本中,它被用在共同和逆變的位置。

我有一個connect方法別處其中設置了一個Input/Output對之間的鏈路:

def connect[T](output: Output[T], input: Input[_ >: T]) = { 
    output.input = Some(input) 
    input.output = Some(output) 
} 

如果我如下調用此方法,得到了一個錯誤類型:

val out = new Output[String] 
val in = new Input[AnyRef] 
connect(out, in) 

錯誤是:

test.scala:17: error: type mismatch; 
found : Output[String] 
required: Output[AnyRef] 
    connect(out, in) 
     ^

我可以通過寫出類型參數來解決這個問題(在這種情況下,我會寫connect[String],但我認爲編譯器應該能夠爲我弄明白這一點。如何更改connect方法以便自動推斷類型參數?


編輯:現在,我做了connectOutput一個方法,因此自動獲得的類型參數。這也有額外的好處,我可以使用中綴記號out connect in,但設計感覺有點尷尬。

我仍然對爲什麼編譯器會出現這種行爲感興趣。我覺得它應該能夠推斷出類型參數。這是否按照指定的方式工作?

+0

您的意思是「不要*在相同類型的值上運行*」 – 2009-07-26 19:17:00

+0

您是否試過向斯卡拉郵件列表提問? – GClaramunt 2009-07-31 18:30:06

回答

6

有時你會如果使用多個參數列表取得更好的成績:在這種情況下

def connect[T](output: Output[T])(input: Input[_ >: T]) = { 
    output.input = Some(input) 
    input.output = Some(output) 
} 

connect(out)(in) 

......而事實上,它的工作原理。

+3

你可以擴展爲什麼這是? *「有時會得到更好的結果」*聽起來不太確定! – 2009-07-27 12:03:06

0

我可能是完全錯誤的,但我認爲問題在於當你將輸入和輸出連接在一起時: 輸入的輸出限於T的子類型,但輸出的輸入被限制爲超類型T,能夠滿足這兩個條件的唯一類型是T.

Input[T] -> Output[ _ <: T ] 
Output[Q] -> Input[ _ >: Q ] 

當與輸出(與替換Q _ <:T)創建輸入你得到:

Input[T]->Input[ _ >: [_ <: T] ] 

同樣作爲

輸入[T] - >輸入[_ <:T <:_]

因此,類型不匹配

0

其實scala類型的inferene現在不能處理「遞歸」。所以如果參數的類型只能在與其他參數搭配的情況下進行傳遞,則不能推斷。但是,如果你使用不同的參數列表scala f(a)(b)(c,d)將按列表推斷類型列表,所以它通常更好地工作。

PS它過於簡單化了,但可以給你一些線索。

相關問題