2016-02-05 51 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的依赖类型是一个聪明的小说 - 事实上,类型从不依赖于实际的运行时值。但事实证明,仅仅通过识别其他类型的类型,就有可能在有限的范围内追踪数值,给人一种依赖于数值的类型的印象。