2014-01-05 35 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

谢谢。你的解释对我很有帮助。我还有一个问题。往上看。你能提供任何见解吗? –

相关问题