为什么在trait中使用抽象修饰符时编译器会在两种情况下报错?

4

我正在练习在线书籍《Scala编程》第一版中有关特征(trait)的章节。

http://www.artima.com/pins1ed/traits.html

这里有两个例子展示了特征的强大之处,分别是丰富薄接口和可叠加修改。以下是实现代码片段:

// example 1
trait Relation[T]
{
  def compare(that: T): Int

  def <(that: T) = compare(that) < 0
  def >(that: T) = compare(that) > 0
  def <=(that: T) =  compare(that) <= 0
  def >=(that: T) = compare(that) >= 0
}

// example 2
trait Doubling extends IntQueue
{
  abstract override def put(a: Int) { super.put(a*2) }
}

以上代码可以正常编译。

我对abstract修饰符的存在很好奇,所以在示例1中,我首先在Relation::compare()前面添加了一个abstract修饰符。也许将abstract标记为compare是合理的,因为它将被子类重写。

// case 1
abstract def compare(that: T): Int

然后编译器就开始抱怨了。

Error:(19, 16) `abstract' modifier can be used only for classes; it should be omitted for abstract members
abstract def compare(that: T): Int
           ^

我认为这条信息表明在trait中不应该使用abstract修饰符。因此,我尝试从示例2中的Doubling :: put中删除abstract修饰符,就像这样:

// case 2
override def put(a: Int) { super.put(a*2) }

但编译器也发出了警告

Error:(35, 36) method put in class IntQueue is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override'
  override def put(a: Int) { super.put(a*2) }
                               ^

我知道在这里使用override修饰符的原因,但我不知道为什么编译器会抱怨我应该加上abstract修饰符。在前面的情况下,编译器只是抱怨我只应该将abstract放在类中吗?

1个回答

5
您说:“我认为该信息表明不应在trait中使用abstract修饰符。” 实际上,这意味着在Scala中,如果一个类有抽象方法,则将其标记为抽象类,但不要在方法本身上使用abstract关键字。编译器知道方法是抽象的,只是因为您没有提供实现。
至于第二个问题,您需要在put的重写上使用abstract关键字的原因是IntQueueput是抽象的。您告诉编译器super.put(a*2)并不是真正尝试调用抽象方法,当然这是行不通的 - 您期望混入提供实现的trait。
更多信息请点击这里

所以在抽象方法前面不需要添加abstract关键字吗?这是因为缺少实现已经提示编译器它是一个抽象的方法? - Chen OT
1
没错。你只需要在第二种情况下使用抽象关键字,即当你重写一个抽象方法并通过super调用它时。在这种情况下,“abstract”这个词并不意味着“这个方法是抽象的”,而是“我意识到这个方法覆盖了一个抽象方法,所以在这个trait之前必须混入实现该方法的trait。” - AmigoNico

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接