Шаг 203.
Основы Kotlin.
Обобщения. Ограничения обобщений

    На этом шаге мы рассмотрим задание таких ограничений.

    Допустим, вы бы хотели гарантировать, что в сундук можно складывать только награды, а не что-нибудь еще. Можете указать ограничение обобщенного типа для решения конкретно этой задачи.

    Для начала объявим классы Coin и Fedora как подклассы нового суперкласса Loot.

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 }
    }

}

open class Loot(val value: Int)

class Fedora(val name: String, value: Int): Loot(value)

class Coin(value: Int): Loot(value)


Рис.1. Добавление суперкласса (Generics.kt)

    Теперь добавим ограничение в объявление параметра обобщенного типа LootBox, чтобы только наследники класса Loot могли использоваться с LootBox.

class LootBox<T : Loot>(item: T) {
    .   .   .   .
}


Рис.2. Ограничение параметра обобщенного типа суперклассом Loot (Generics.kt)

    В примере вы добавили ограничение для обобщенного типа Т, определив его как :Loot. Теперь в сундук можно положить только те награды, которые являются наследниками класса Loot.

    Возможно, у вас возник вопрос: зачем вообще нужен параметр Т? Почему просто не использовать тип Loot? Параметр Т позволяет обращаться к награде определенного типа и одновременно допускает помещать в сундук награды любого вида. То есть сундук LootBox будет хранить награду не типа Loot, а, например, типа Fedora. И конкретный тип Fedora будет определяться с помощью Т.

    Объявив тип награды как Loot, вы точно так же смогли бы поместить в сундук только наследников Loot, но информация о том, что в сундуке хранится награда Fedora, была бы утрачена. Использование конкретного типа Loot, например, не позволило бы скомпилировать следующий код:

    val lootBox<Loot>: LootBox<Fedora> = LootBox(
            Fedora("a dazzling fuschia fedora", 15))
    val fedora: Fedora = lootBox.item
    // Несовпадение типов - Требуется: Fedora,
    // Имеется: Loot
}

    И вы уже не узнаете, что сундук LootBox хранит что-то отличное от Loot. Используя ограничение типов, возможно ограничить содержимое сундука до Loot и сохранить подтип награды в сундуке.

    На следующем шаге мы рассмотрим ключевые слова vararg и get.




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