Шаг 202.
Основы Kotlin.
Обобщения. Несколько параметров обобщенного типа

    На этом шаге мы рассмотрим использование обобщенных типов в параметрах функций.

    Обобщенная функция или тип также могут иметь несколько параметров обобщенного типа. Допустим, вам хочется ввести еще одну функцию - fetch(), которая принимает функцию, преобразующую награду одного вида в другой, например в монеты. Количество возвращаемых монет зависит от ценности исходной награды. Такое преобразование реализует функция высшего порядка lootModFunction(), которая передается в fetch().

    Добавьте новую функцию fetch() в LootBox, которая будет принимать функцию, преобразующую награду.

class LootBox<T>(item: T) {
    var open = false
    private var loot: T = item

    fun fetch(): T? {
        return loot.takeIf { open }
    }

    fun <R> fetch(lootModFunction: (T) -> R): R? {
        return lootModFunction(loot).takeIf { open }
    }

}


Рис.1. Использование нескольких параметров обобщенного типа (Generics.kt)

    В примере мы добавили в определение функции новый параметр обобщенного типа R , сокращенно от "return" (возврат), потому что он определяет тип возвращаемого значения. Мы поместили параметр обобщенного типа в угловых скобках непосредственно перед именем функции: fun <R> fetch. Функция fetch() возвращает значение типа R?, то есть версию R с поддержкой значения null.

    Вы также указали, что lootModFunction (посредством объявления типа функции (T)->R) принимает аргумент типа Т и возвращает тип R. Испытайте объявленную новую функцию fetch(). В этот раз передайте функцию преобразования награды в качестве аргумента.

.   .   .   .
fun main(args: Array<String>) {
    val lootBoxOne: LootBox<Fedora> = LootBox(
            Fedora("a generic-looking fedora", 15))
    val lootBoxTwo: LootBox<Coin> = LootBox(Coin(15))

    lootBoxOne.fetch()?.run {
        println("You retrieve $name from the box!")
    }

    val coin = lootBoxOne.fetch() {
        Coin(it.value * 3)
    }
    coin?.let { println(it.value) }

}
Файл с проектом можно взять здесь.


Рис.2. Передача функции преобразования награды в качестве аргумента (Generics.kt)

    Новая версия функции fetch(), объявленная вами, возвращает тип переданной лямбды R. Вы вернули Coin? из лямбды, поэтому тип R в этом случае Coin?. Но новая версия fetch() более гибкая и может возвращать не только монеты, следовательно, функция fetch() вернет значение того же типа, что и лямбда, так как R зависит от типа значения, возвращаемого анонимной функцией.

    lootBoxOne содержит награду типа Fedora. Но ваша новая функция fetch() вернет Coin? вместо Fedora?. Это возможно благодаря дополнительному параметру обобщенного типа R.

    Функция lootModFunction(), передаваемая в fetch(), вычисляет количество монет, умножая ценность награды в сундуке на три.

    Запустите Generics.kt. В этот раз вы увидите название награды fedora (шляпа), найденной в сундуке, и ее ценность в монетах:

You retrieve a generic-looking fedora from the box!
45


Рис.3. Результат работы приложения

    На следующем шаге мы рассмотрим ограничения обобщений.




Предыдущий шаг Содержание Следующий шаг