2016-02-05 50 views
1

考慮:瞭解相關類型

scala> sealed trait Parent 
defined trait Parent 

scala> case object Boy extends Parent 
defined object Boy 

scala> case object Girl extends Parent 
defined object Girl 

scala> trait F { 
    | type A 
    | def x: A 
    | } 
defined trait F 

scala> case object FImpl extends F { 
    | override type A = Parent 
    | def x: Parent = Boy 
    | } 
defined object FImpl 

然後我定義的方法:

scala> def foobar(f: F)(matcher: f.A => Boolean): Boolean = 
    | matcher(f.x) 
foobar: (f: F)(matcher: f.A => Boolean)Boolean 

scala> foobar(FImpl)(_ match { case Boy => true; case Girl => false}) 
res3: Boolean = true 

我很困惑,如何工作的。編譯器在編譯時必須知道f.A的類型嗎?

+0

不確定你在問什麼。你期望這不會編譯? –

+0

@ m-z - Owen很好地捕捉到了我不清楚的問題 - 「當f是運行時值時,編譯器如何看到成員f.A?' –

回答

0

你的問題基本上是:當f是一個運行時值時,編譯器如何看到成員f.A?答案是它沒有。在句法上,f.A看起來像是訪問f的成員,但實際上它僅依賴於f的類型。

當你寫:

object FImpl extends F { 
    override type A = Parent 
    def x: Parent = Boy 
} 

FImpl定義了一個新的單項式,被稱爲FImpl.type。所以,FImpl.type#AParent

當你調用foobarf.type是確定與FImpl.type,所以f.A又名f.type#AFImpl.type#A又名Parent

考慮以下兩個例子:

def needsParent(p: Parent) = ??? 
def foobar(f: F)(matcher: f.A => Boolean) = ??? 

foobar(FImpl)(needsParent) // Works 
foobar(FImpl: F)(needsParent) // Does not work 

雖然運行時的值是相同的,其種類不同,所以編譯器接受一個並拒絕其它。換句話說,Scala的依賴類型是一個聰明的小說 - 事實上,類型從不依賴於實際的運行時值。但事實證明,僅僅通過識別其他類型的類型,就有可能在有限的範圍內追蹤數值,給人一種依賴於數值的類型的印象。