Если черта A расширяет B, то смешивание в A дает вам точно B плюс все, что A добавляет или расширяет. Напротив, если черта A имеет собственную ссылку, которая явно указана как B, тогда родительский класс должен также смешиваться с B или с потомком B (и сначала смешивать его , что важно).
Это самое важное отличие. В первом случае точный тип B кристаллизуется в точке A, расширяющей его. Во втором случае разработчик родительского класса решает, какая версия B используется в точке, где создается родительский класс.
Другое отличие состоит в том, что A и B предоставляют методы с одинаковыми именами. Если A расширяет B, метод A переопределяет B. Когда A смешивается после B, метод A просто выигрывает.
Напечатанная ссылка на себя дает вам гораздо больше свободы; связь между A и B ослаблена.
ОБНОВИТЬ:
Поскольку вы не уверены в пользе этих различий ...
Если вы используете прямое наследование, вы создаете черту A, которая является B + A. Вы установили отношения в камне.
Если вы используете типизированную ссылку на себя, то любой, кто хочет использовать вашу черту A в классе C, может
- Смешайте B и затем A в C.
- Смешайте подтип B и затем A в C.
- Смешайте A в C, где C является подклассом B.
И это не предел их опций, учитывая то, как Scala позволяет создавать экземпляр свойства непосредственно с помощью блока кода в качестве его конструктора.
Что касается разницы между выигрышем метода А , поскольку А смешивается последним, по сравнению с А, расширяющим В, рассмотрим это ...
Когда вы смешиваете в последовательности признаков, всякий раз, когда foo()
вызывается метод , компилятор переходит к последней смешанной характеристике, чтобы искать foo()
, затем (если не найден) он проходит последовательность влево, пока не найдет характеристику, которая реализует foo()
и использует который. A также имеет опцию call super.foo()
, которая также проходит по последовательности влево, пока не найдет реализацию, и так далее.
Так что, если A имеет типизированную собственную ссылку на B и автор A знает, что B реализует foo()
, A может вызвать, super.foo()
зная, что, если ничего не предоставит foo()
, B сделает. Тем не менее, создатель класса C имеет возможность отбросить любую другую черту, в которой реализованы foo()
, и A получит это вместо этого.
Опять же , это гораздо более мощные и менее жесткие ограничения , чем вытянутая B и прямой вызов версии B по foo()
.