Вони називаються обмеженнями узагальненого типу . Вони дозволяють вам із класу, параметризованого типом або ознакою, додатково обмежувати один із його параметрів типу. Ось приклад:
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 Ais 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]. По суті, ви пишете спеціальний код для певних типів списків.