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



Книга Как работают обобщения в 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")
}


353   0  

Comments

    Ничего не найдено.