Scala:'type A = XXX' 和 'final type A = XX' 之间的区别?

Scala: Difference between 'type A = XXX' and 'final type A = XX'?

假设我有一个抽象类型 AA 和具体类型 XXX:

trait AA {
  type A = XXX
  final type B = XXX
}

在这种情况下,在AA的任何子类中,类型A和类型B都不能被覆盖,因此关键字final显得完全多余。这个说法正确吗?

很难证明它们完全相同,但我要证明它们是完全相同的,只是减去一些无用的怪癖。

无用的怪癖

首先,也是最明显的,它们给出了不同的错误信息。但这还不是全部:技术上可以覆盖 A,但不能将其覆盖为 XXX:

以外的任何内容
trait A1 extends AA {
  override type A = XXX  // Compiles, but doesn't really do anything.
}

另一方面,您永远无法覆盖 B:

trait A2 extends AA {
  override type B = XXX  // Does not compile.
}

有什么有用的区别吗?

再一次,我要争辩说没有。在非常详细的 answer to the question Is it possible to override a type field, Whosebug user 0__ 注释中

type T = C inevitably fixes T, which would kind of correspond to making a method final.

You can now easily see that it must be forbidden to further 'override' T

之后是一些解释,如果您可以将 T 覆盖为不同的类型,类型系统将如何不一致。有关详细信息,请参阅该答案。