为什么Scala在分配给抽象类型时会丢失实际类型?

时间:2014-01-05 22:43:57

标签: scala abstract-type

给出以下代码:

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. 您有解决方案吗?

  3. 我在版本3.0.2-vfinal-20131028-1923-Typesafe中从Scala-SDK的Scala工作表中收到以下错误消息:

    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
    

    好的,省略“bar”方法的返回类型声明会从Scala工作表中留下以下信息:

    > res0: scrap.Bar{type Parent = scrap.Foo; val parent: Some[scrap.Foo]} = scra
                                                      //| p$Foo$$anon$1@3bba229e
    

    有没有办法给这个类型一个像样的名字,理想情况下是“Foobar#Parent”?

1 个答案:

答案 0 :(得分:1)

中会发生什么
(new Foo).bar().parent.get.bar()

是:

  • new FooFoo
  • .bar()中的
  • Foo属于Bar类型(声明如此,即使实际结果超过此值)
  • .parent中的
  • Bar未重新定义,父级也未重新定义,因此只有parent: Parent <: FooBar从FooBar继承。将使用绑定的FooBar
  • FooBar中没有bar,因此.parent.bar()失败。

如果你在Foo中声明

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的子类型将被允许返回具有不同Bar类型的Parent


关于您的更新: 我不确定为什么我希望将该类型显示为FooBar#Parent,这几乎没有任何说明,但无论如何,我认为你不能说服scala这样做。

简单显示的简单方法是命名您返回的类型,而不是匿名扩展Bar。如果你不想这样做,你至少要声明方法的返回类型,这无论如何都是好的做法。否则,scala将以最大精度显示它所推断的内容。你可以使用def Bar: Bar {type Parent = Foo} = ...,或者你可以为它声明一个类型别名(最好是在Foo之外):

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