2014-01-05 59 views
1

考慮下面的代碼:爲什麼Scala在分配給抽象類型時會丟失實際的類型?

abstract class Foobar { 

    type Parent <: Foobar 

    def parent: Option[Parent] 

} 

class Foo extends Foobar { 

    type Parent = Nothing 

    val parent = None 

    // *** 
    // Taking the explicit declaration of the "bar" method's return type 
    // "Bar" away convinces Scala to compile the code. In other words: 
    // 
    //  def bar() = new Bar 
    // *** 
    def bar(): Bar = new Bar { 

    type Parent = Foo 

    val parent = Some(Foo.this) 

    } 

} 

abstract class Bar extends Foobar 

(new Foo).bar().parent.get.bar() 

我的問題:

  1. 你能解釋一下爲什麼會這樣?請參閱上面的內嵌評論。

  2. 你有解決方案嗎?

我碰到斯卡拉-SDK的斯卡拉工作表以下錯誤消息版本3.0.2-vfinal-20131028-1923類型安全:

Multiple markers at this line 
    - value bar is not a member of scrap.Bar#Parent 
    - value bar is not a member of scrap.Bar#Parent 

確定,離開了 「欄」方法的返回類型的聲明讓我從斯卡拉工作表以下信息消息:

> res0: scrap.Bar{type Parent = scrap.Foo; val parent: Some[scrap.Foo]} = scra 
                //| [email protected] 

有沒有辦法給這個類型一個體面的名字,非常「Foobar的#父」?

+1

請張貼的編譯器錯誤。我知道這看起來很迂腐,但未來版本的scalac可能會有不同的表現。 –

回答

1

(new Foo).bar().parent.get.bar() 

會發生什麼事是:

  • new FooFoo
  • Foo.bar()Bar型(聲明所以,即使實際的結果更比)
  • .parent in Bar is no t重新定義,Parent也不是,所以它只是從FooBar繼承的parent: Parent <: FooBar。將使用綁定的FooBar
  • FooBar中沒有bar,所以.parent.bar()失敗。

如果您在富

聲明
def bar(): Bar { type Parent = Foo} = new Bar {// same as your code} 

或者乾脆

def bar() = new Bar {// same } 

讓類型推斷,它工作正常。

如果您聲明def bar(): Bar,這是打字停止的地方。就像您聲明def bar(): Any = whatever一樣,它不會考慮whatever的類型。並且Foo的子類型將被允許以不同的Parent類型返回Bar


關於你提到的更新: 我不知道爲什麼我會想有這種類型顯示爲FooBar#Parent,它告訴接近沒什麼,但無論如何,我不認爲你能說服斯卡拉做。

簡單顯示的簡單方法是將您返回的類型命名爲Bar而不是匿名。如果你不想這樣做,你至少要聲明方法的返回類型,無論如何這是一個好習慣。否則,scala會以最大的精度顯示它推斷的內容。您可以使用def Bar: Bar {type Parent = Foo} = ...,或者你可以聲明一個類型別名爲(最好是富外):

type BarWithFooParent : Bar {type Parent = Foo } 
def bar(): BarWithFooParent = new Bar() { … } 
+0

謝謝。你的解釋對我很有幫助。我還有一個問題。往上看。你能提供任何見解嗎? –

相關問題