2012-01-23 177 views
1

我有一個導致類似不匹配的情況,我似乎無法解決。下面的代碼的簡化版本:Scala類型不匹配錯誤

abstract class Msg 

trait Channel[M <: Msg] { 
    def receive(): M 
    def ack(envelope: M) 
} 

object ChannelSender { 
    private var channel : Channel[_ <: Msg] = _ 
    def assignChannel(channel : Channel[_ <: Msg]) = this.channel = channel 

    def test() { 
    val msg = channel.receive() 
    channel.ack(msg) // Type mismatch here 
    } 
} 

來自編譯器的錯誤是:

類型不匹配;發現:msg.type(與基礎型 com.msgtest.Envelope)要求:_ $ 1,其中類型_ $ 1 <: com.msgtest.Envelope

我能做出什麼樣的改變得到這個工作?此外,這些變化,需注意以下具體實施編譯:

class SomeMsg extends Msg 

object SomeChannel extends Channel[SomeMsg] { 
    def receive(): SomeMsg = { null.asInstanceOf[SomeMsg] } 
    def ack(envelope: SomeMsg) {} 
} 

object Setup { 
    ChannelSender.assignChannel(SomeChannel) 
} 

回答

4

我能得到它的Scala 2.9下編譯兩個變化,

trait Channel[M <: Msg] { 
    type M2 = M  // Introduce a type member that's externally visible 
    def receive(): M2 
    def ack(envelope: M2) 
} 

object ChannelSender { 
    private var channel : Channel[_ <: Msg] = _ 
    def assignChannel(channel : Channel[_ <: Msg]) = this.channel = channel 

    def test() { 
    val c = channel // An immutable value, so that c.M2 is stable 
    val msg = c.receive() 
    c.ack(msg)  // OK now 
    } 
} 

的第一個變化是使用一個不變的值val c = channel,所以路徑依賴類型c.M2總是意味着相同的東西。第二個改變是在特徵Channel中引入類型成員type M2 = M。我不完全確定爲什麼這是必要的(可能是一個錯誤?)。有一點要注意的是c.M2是一個有效的類型,而c.M是未定義的。

+0

好東西,謝謝!我不明白爲什麼這些變化都是必要的。如果Channel.M在外部不可見,那麼它有什麼用處?我們是否總是需要爲類型參數創建一個類型別名,以便在trait/class之外使用?對於ChannelSender的更改,由於我在同一'channel'對象上調用'receive()'和'ack',路徑依賴類型c.M2是不是意味着相同的事情? – Josh

+0

偉大的問題。對於第一個,我不知道答案。也許有人對郵件列表有更多的瞭解可能會有所幫助。對於第二個,我同意Scala可以發現在這種情況下'channel'對象沒有改變,但是我認爲一般Scala會做出簡化的假設,即'var'不可信以保持不變。 –