Шаблон класса типов дает возможность реализовать специальный полиморфизм .
То есть, если у вас есть какая-то полиморфная функция foobar
, которая должна работать со многими различными типами T
, а затем у вас есть конкретный тип T1
, который не реализует интерфейс, обеспечивающий foobar
, вы можете присоединить foobar
до T1
специальным образом следующим образом:
trait FoobarTypeclass[T] {
def foobar(t: T): Unit
}
def functionThatRequiresFoobar[T: FoobarTypeclass](t: T): Unit = {
for (i <- 1 to 10)
implicitly[FoobarTypeclass[T]].foobar(t)
}
// note that `functionThatRequiresFoobar` knows nothing about `T1` at this point
class T1
implicit object AdHocFoobarForT1 extends FoobarTypeclass[T1] {
def foobar(t: T1): Unit = println("foobar now works on T1, awesome!")
}
functionThatRequiresFoobar(new T1) // but here, it works anyway!
В приведенном выше примере вы видите две вещи:
- Ни
FoobarTypeclass
, ни functionThatRequiresFoobar
не должны ничего знать о существовании конкретного типа T1
- Тип
T1
также не должен ничего знать о FoobarTypeclass
или functionThatRequiresFoobar
.
Это означает, что T1
и functionThatRequiresFoobar
полностью отделены . Но в последней строке примера,
functionThatRequiresFoobar(new T1)
в любом случае работает просто замечательно, потому что класс типов AdHocFoobarForT1
присоединяет реализацию foobar
к классу T1
специальным образом.
Аналогичным образом, вы можете использовать этот шаблон для «реализации интерфейсов в режиме ad-hoc» в классах, которые не объявляют никаких соответствующих интерфейсов в своей иерархии наследования. Это, в свою очередь, позволяет вам склеивать совершенно независимые библиотеки, просто предоставляя несколько классов типов здесь и там.