Typeclass example
// Тайпкласс Animal (для полноты картины добавил метод hello, иначе был бы совсем тривиальный пример) | |
// Animal полностью абстрагирован от низлежашего типа A | |
trait Animal[A] { | |
def word: String | |
def talk() { println(word) } | |
def hello(a: A): String | |
} | |
// Обертка над тайпклассом Animal, чтобы можно было писать cat.hello, а не animal.hello(cat) | |
// AnimalOps полностью дублирует методы, определённые в Animal, но также может содержать еще и дополнительные методы. | |
final class AnimalOps[A](val a: A)(implicit val animal: Animal[A]) { | |
def word = animal.word | |
def talk() = animal.talk() | |
def hello = animal.hello(a) | |
} | |
object animal { | |
implicit def toAnimalOps[A](a: A)(implicit animal: Animal[A]) = new AnimalOps(a)(animal) | |
} | |
// Собственно, ADT. Добавил поле name для более наглядного примера. | |
// Заметьте, Cat - ничего не знает про Animal, а Animal ничего не знает про Cat. | |
// Эти сущности могут быть определены независимо, в разных пространствах имен или даже в разных модулях, | |
// в отличие от примера eax, где Cat зависит от Animal через наследование (в этом и отличие тайпкласса | |
// от примеси). | |
case class Cat(val name: String) | |
// Реализация тайпкласса Animal для Cat. Эта сущность может быть определена вообще в третьем модуле | |
trait CatAnimal extends Animal[Cat] { | |
def word = "Meow!" | |
def hello(cat: Cat) = s"Hello, my name is ${cat.name}!" | |
} | |
object cat { | |
implicit val instance = new CatAnimal {} | |
} | |
// Еще одна реализация тайпкласса Animal, которая расширяет CatAnimal. | |
trait HappyCatAnimal extends CatAnimal { | |
override def word = super.word + ":)" // Переопределение методов - зло. Его желательно избегать. | |
} | |
object happyCat { | |
implicit val instance = new HappyCatAnimal {} | |
} | |
// Пример использования Animal и Cat с реализацией CatAnimal | |
object Main extends App { | |
import animal._ | |
import cat._ | |
val cat = new Cat("Kittie") | |
cat.talk() // Печатает Meow! | |
} | |
// Пример использования Animal и Cat уже с реализацией HappyCatAnimal (код идентичен с точностью до импортов) | |
object Main2 extends App { | |
import animal._ | |
import happyCat._ | |
val cat = new Cat("Kittie") | |
cat.talk() // Напечатает Meow!:) | |
} |
This comment has been minimized.
This comment has been minimized.
Я на практике вообще на Scala ничего не писал кроме пары мелких программ не для production |
This comment has been minimized.
This comment has been minimized.
У нас на практике все примерно так и есть. Очень много тайпклассов и иплиситов. Полет нормальный. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
А на практике в Scala получалось использовать?