抽象类型+自我类型+类型覆盖,错误"值xxx不是Component.this.T"的成员。

时间:2016-02-07 10:24:59

标签: scala abstract-type self-type

错误如下所示:

trait Base { type T }

trait Component { self: Base =>
  override type T <: MyT

  val factory: Factory 

  trait Factory { def get_t: T }

  trait MyT { def xxx: Unit }

  class User {
    val t: T = factory.get_t

    def yyy = t.xxx
  }
}

trait ComponentImpl { self: Component => 
  type T = TImpl

  class TImpl extends MyT {
    def xxx = println("xxx")
  }

  val factory = new Factory {
    def get_t: T = new TImpl
  }
}

我收到错误:

<console>:26: error: value xxx is not a member of Component.this.T
       def yyy = t.xxx

有了一些冗余,我还发布了@slouc和@Kolmar建议的最小例子

trait Base { type T }

trait MyT { def xxx: Unit }

trait Component { self: Base =>
  override type T <: MyT
  val t: T
  def yyy = t.xxx // error
} 

似乎我无法利用约束给出的增量,部分知识。

我的问题不是关于方法,而是我有兴趣了解错误背后的原因。

为了提供更多上下文,我还要补充一点,当我尝试将继承关系转换为两个组件之间基于自我类型的关系时,我遇到了这个问题。

2 个答案:

答案 0 :(得分:2)

使用自我类型注释,您基本上告诉编译器自引用具有不同的类型

self: Base

如果你使用任何普通表达式执行此操作,那么现在唯一的类型就是Base。不知何故,类型注释作为特殊情况处理并保持其原始类型,我们实际上看起来的类型是

self: Base with Component

现在,不知怎的,如果你引用Component.this似乎在被覆盖的类型成员的情况下丢失了这些信息(或者可能覆盖错误的方法,但我看不出任何解释这不是一个bug)

现在,如果您实际注释此类型,问题就会消失:

trait Component { self: Base with Component => ... }

这也清楚地表明这是一个错误,因为这很好用:

trait Component { self: Base =>
  val v:  Base with Component = self
}

这实际上是一个已知的Bug:

https://issues.scala-lang.org/browse/SI-7255?jql=text%20~%20%22override%20self%20type%20abstract%22

答案 1 :(得分:1)

有趣的问题。这是一个简单的例子:

scanf()

请注意以下三点:

1.将自我类型注释更改为继承可以解决所有问题:

trait Base { type T }

trait MyT { def xxx: Unit }

trait Component { self: Base =>
  override type T <: MyT
  val t: T
  def yyy = t.xxx // error
}

2.自我类型的超越方法没有问题:

trait Component extends Base {
  override type T <: MyT
  val t: T
  def yyy = t.xxx
}

3.如果不是缩小类型T而是使其具体化,那么最重要的是:

trait Base { def foo }

trait Component { self: Base =>
  override def foo = println("foo")
}

所以,我对问题的表述是 - 为什么在继承的情况下,所有三种情况都可以正常工作(1.覆盖方法,2。通过缩小覆盖抽象类型成员,3。通过制作覆盖抽象类型成员具体),但在自我类型的情况下第二种情况是有问题的,而其他两种工作正常吗?

考虑修改您的问题(删除trait Base { type T } trait Component { self: Base => override type T = List[Int] val t: T def yyy = t.reverse } ComponentImpl等),以便为其他读者简化。