Как работают обобщения в Kotlin

Одна из главных задач разработчика  —  писать лаконичный код и избегать дублирования. Обобщения (generics) относятся к числу функциональностей, которые улучшают производительность, способствуют созданию меньших объемов кода и сокращению случаев его переиспользования и т. д. Следовательно, с ними обязательно нужно познакомиться. 

Зачем нужны обобщения? 

class SearchUtil(private val list: List<Int>) {
fun searchItem(element: Int, foundItem: (element: Int?) -> Unit) {
val itemFoundList = list.filter {
it == element
}
if (itemFoundList.isNullOrEmpty())
foundItem(null)
else
foundItem(itemFoundList.first())
}
}

fun search() {
val searchUtil = SearchUtil(listOf(25, 46, 35))
searchUtil.searchItem(element = 25) {
println("Search result : $it")
}
}

fun main() {
search()
}

Как видно, класс SearchUtil принимает список целых чисел в качестве параметра. Функция searchItem принимает на входе целое число (которое нужно найти) и возвращает результат. Кажется, все отлично. В чем же проблема? 

Допустим, требуется найти элемент, который является списком строк или объектов. Ваши действия? Рассмотрим 2 возможных варианта решения.

  1. Создать еще один класс SearchUtil и функцию searchItem, которые примут строки или тип объекта и вернут результат. 
  2. Применить обобщения. 

Очевидно, что первое решение не подходит. Оно обернется написанием избыточного кода, многие фрагменты которого будут дублироваться. В данном случае помогут обобщения. 

Что такое обобщения?

Согласно официальной документации: 

Обобщения  —  это классы, структуры, интерфейсы и методы, имеющие плейсхолдеры (параметры типов) для одного или более хранимых или применяемых типов. Класс обобщенной коллекции может использовать параметр типа как плейсхолдер для типа хранимых в нем объектов. Параметры типа выступают как типы его полей и типы параметров методов. Обобщенный метод может задействовать свой параметр типа как тип возвращаемого значения или как тип одного из его формальных параметров. 

Короче говоря: 

Обобщения  —  это гибкая система, позволяющая работать с любыми типами данных. Она снимает с вас все заботы о типах и поручает их компилятору. 

Проще объяснить уже невозможно. 

Применение обобщений 

Перепишем ранее рассмотренный пример, используя обобщения. Для преобразования класса SearchUtil в обобщения нужно внести в него изменения: 

class SearchUtil<T>(private val list: List<T>)

T указывает на возможность любого типа в качестве аргумента. 

Кроме того, необходимо изменить функцию searchItem

fun searchItem(element: T, foundItem: (element: T?) -> Unit)

Теперь мы можем задействовать любой тип по желанию: 

val searchUtil = SearchUtil(list = listOfObjects)
val searchUtil = SearchUtil(list = listOfNumber)

Вышеуказанный код будет работать без проблем. Рассмотрим реальный пример: 

data class Person(val name: String, val email: String, val age: Int)

fun search() {
val henry = Person(name = "Henry", email = "[email protected]", age = 24)
val robert = Person(name = "Robert", email = "[email protected]", age = 22)
val tom = Person(name = "Tom", email = "[email protected]", age = 25)

val listOfPerson = listOf(henry, robert, tom)
val searchUtil = SearchUtil(list = listOfPerson)
searchUtil.searchItem(element = henry) {
println("Search result : $it")
}
}

class SearchUtil<T>(private val list: List<T>) {
fun searchItem(element: T, foundItem: (element: T?) -> Unit) {
val itemFoundList = list.filter {
it == element
}
if (itemFoundList.isNullOrEmpty()) foundItem(null) else
foundItem(itemFoundList.first())
}
}

fun main() {
search()
}

Мы создаем класс данных Person и выполняем операцию поиска по listOfPerson. При необходимости провести поиск по списку целых чисел мы можем сделать это без каких-либо изменений в SearchUtil или searchItem .

val listOfNumbers = listOf(25, 46, 35)
val searchUtil = SearchUtil(list = listOfNumbers)
searchUtil.searchItem(element = 25) {
    println("Search result : $it")
}

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Farhan Tanvir: How to Use Generics in Kotlin

Предыдущая статья9 советов по работе с консолью JavaScript, которые помогут оптимизировать отладку
Следующая статьяВведение в бинарный поиск