Вони називаються обмеженнями узагальненого типу . Вони дозволяють вам із класу, параметризованого типом або ознакою, додатково обмежувати один із його параметрів типу. Ось приклад:
case class Foo[A](a:A) { // 'A' can be substituted with any type
// getStringLength can only be used if this is a Foo[String]
def getStringLength(implicit evidence: A =:= String) = a.length
}
Неявний аргумент evidence
подається компілятором, iff A
is String
. Ви можете вважати це доказом, що A
це String
- сам аргумент не важливий, лише знаючи, що він існує. [редагувати: ну, технічно це насправді важливо, оскільки це являє собою неявну конверсію з A
в String
, саме це дозволяє вам дзвонити, a.length
а не компілятор кричати на вас]
Тепер я можу використовувати його так:
scala> Foo("blah").getStringLength
res6: Int = 4
Але якщо я спробував використовувати його із Foo
вмістом, що не містить String
:
scala> Foo(123).getStringLength
<console>:9: error: could not find implicit value for parameter evidence: =:=[Int,String]
Ви можете прочитати цю помилку як "не вдалося знайти доказ того, що Int == String" ... це так, як має бути! getStringLength
накладає додаткові обмеження щодо типу, A
ніж того, що Foo
взагалі вимагає; а саме ви можете посилатися лише getStringLength
на a Foo[String]
. Це обмеження виконується під час компіляції, що класно!
<:<
і <%<
працювати аналогічно, але з незначними варіаціями:
A =:= B
означає, що A повинен бути саме B
A <:< B
означає, що A повинен бути підтипом B (аналогічно обмеженню простого типу <:
)
A <%< B
означає, що A має бути видимим як B, можливо, шляхом неявного перетворення (аналогічного простому обмеженню типу <%
)
Цей фрагмент від @retronym є хорошим поясненням того, як подібні речі використовувались і як узагальнені обмеження типу спрощують його зараз.
ДОБАВЛЕННЯ
Щоб відповісти на ваше подальше запитання, правда, приклад, який я наводив, досить надуманий і не очевидно корисний. Але уявіть, як використовувати його для визначення чогось типу List.sumInts
методу, який додає список цілих чисел. Ви не хочете, щоб цей метод використовувався на будь-якому старому List
, лише на List[Int]
. Однак List
конструктор типів не може бути таким обмеженим; ви все ще хочете мати змогу мати списки струн, футів, смуг та ін. Таким чином, розміщуючи узагальнене обмеження типу sumInts
, ви можете переконатися, що саме цей метод має додаткове обмеження, яке може бути використане лише на a List[Int]
. По суті, ви пишете спеціальний код для певних типів списків.