Якщо ознака A поширюється на B, то змішування в A дає точніше B плюс те, що додає або розширює A. На відміну від цього, якщо ознака A має власне посилання, яке явно вводиться як B, то кінцевий батьківський клас також повинен змішуватися з B або низхідним типом B (і змішувати його спочатку , що важливо).
Це найважливіша відмінність. У першому випадку точний тип В кристалізується в точці А, яка розширює його. По-друге, дизайнер батьківського класу отримує рішення про те, яку версію B використовуватиме, в точці, де складається батьківський клас.
Інша відмінність полягає в тому, де A і B надають методи з однойменною назвою. Якщо A поширюється на B, метод A переосмислює B. Якщо A замішується після B, метод A просто виграє.
Набране самонавіювання дає вам набагато більше свободи; з'єднання між А і В є вільним.
ОНОВЛЕННЯ:
Оскільки вам не зрозуміло користь цих відмінностей ...
Якщо ви використовуєте пряме успадкування, ви створюєте ознаку A, яка є B + A. Ви встановили відносини в камені.
Якщо ви використовуєте набрану самостійну посилання, будь-хто, хто хоче використовувати вашу ознаку А в класі С, міг би
- Змішайте B, а потім A в C.
- Змішайте підтип B, а потім A в C.
- Змішайте A в C, де C є підкласом B.
І це не межа їх можливостей, враховуючи те, як Scala дозволяє інстанціювати ознаку безпосередньо з блоком коду як її конструктором.
Щодо різниці між виграшним методом A , оскільки A змішаний останнім, порівняно з A, що розширюється B, врахуйте це ...
Якщо ви змішуєте в послідовності ознак, кожного разу, коли використовується метод foo()
, компілятор переходить до останньої ознаки, змішаної, щоб шукати foo()
, тоді (якщо її не знайдено), вона переміщає послідовність зліва, поки не знайде ознаку, яка реалізує foo()
та використовує що. Також є можливість викликати super.foo()
, який також проходить послідовність зліва, поки не знайде реалізацію тощо.
Отже, якщо A має введене само посилання на B, і письменник A знає, що B реалізує foo()
, A може зателефонувати, super.foo()
знаючи, що якщо нічого іншого не передбачено foo()
, B буде. Однак у творця класу C є можливість скинути будь-яку іншу ознаку, в якій реалізується foo()
, і A отримає це замість цього.
Знову ж , це набагато більш потужні і менш жорсткі обмеження , ніж витягнута B і прямий виклик версії B по foo()
.