Программирование | Отладка | Web-технологии | Microsoft Office | Теор.информатика | Исслед-е операций | Операц. сис-мы | Новости |
Проектирование ИС | Исск. инт-т | Трансляторы | Об авторах | Карта сайта | Поиск |
Язык программирования Turbo Pascal |
Среда программирования Delphi 6 |
Язык программирования C++ |
Язык программирования C# |
Язык программирования Assembler |
Язык программирования Go |
Язык программирования Haskell |
Язык программирования Java |
Язык программирования Kotlin |
Язык программирования LISP |
Язык программирования Prolog |
Язык программирования Python |
Параллельные алгоритмы |
Сети Петри |
Начала |
Отладчик Turbo Debugger |
Основы HTML |
Технология Flash |
Язык программирования Perl |
Основы языка PHP |
Основы PhotoShop |
Основы JavaScript |
Основы CSS |
Основы CorelDRAW |
Библиотека jQuery |
Текстовый процессор Microsoft Word |
Электронные таблицы Microsoft Excel |
Система управления базами данных Microsoft Access |
Использование VBA в Microsoft Excel |
Место информатики в системе наук |
Общие сведения об информации |
Кодирование информации в теории Шеннона |
Основные понятия теории алгоритмов |
Классические формализации понятия 'алгоритм' |
Понятие рекурсии |
Сложность алгоритма |
Методы разработки алгоритмов |
Сложность задачи |
Информационное моделирование |
Основные понятия теории графов |
Алгоритмы поиска на графах |
Матроиды. 'Жадные' алгоритмы |
Динамическое программирование |
Алгоритмы |
UNIX и Linux |
Унифицированный язык моделирования UML |
Введение в машинное обучение с использованием Python |
Основы создания нейросети на Python |
Глубокое обучение на Python |
Начала |
Динамические структуры данных |
Библиотека RX |
Основные классы и события Delphi |
Основные компоненты Delphi |
Организация потоков |
Технология COM |
Язык программирования Object Pascal |
Локальные БД в Delphi |
Библиотека OWL |
Библиотека Qt |
Библиотека STL |
Библиотека шаблонов классов Borland |
Основы компьютерной графики |
Динамические структуры данных |
Начала |
Обработка исключительных ситуаций |
Оптимизация с помощью ассемблера |
Основы объектно-ориентированного программирования |
Потоки ввода-вывода |
Разное |
Редактор Resource Workshop |
Среда Visual C++ |
Программирование в Microsoft Visual C++ 2010 |
Технология CUDA |
Технология OLE |
Начала |
16-битное программирование |
32-битное программирование |
Основы логического программирования |
Динамические структуры данных |
Visual Prolog |
Библиотека PyQt5 |
Библиотека Tkinter |
Визуализация данных |
Начала |
Задачи ComputerScience |
Рекурсия |
Однострочники |
Вкладка RXControls |
Вкладка RXDBAware |
Вкладка RXTools |
Вкладка Standard |
Вкладка Additional |
Создание Internet-приложений |
Вкладка System |
Вкладка Win32 |
Вкладка Servers |
Технология ADO |
Вкладка QReport |
Вкладка InterBase |
Вкладка Dialogs |
Начала |
Среда программирования. Язык С/С++ |
На этом шаге мы рассмотрим необходимость использования этих конструкций.
Для дальнейших изменений ваших параметров обобщенного типа Kotlin предоставляет ключевые слова in и out. Чтобы посмотреть на их работу, создайте простой обобщенный класс Barrel в новом файле с именем Variance.kt.
class Barrel<T>(var item: T)
Рис.1. Объявление Barrel (Variance.kt)
Для экспериментов с Barrel добавим функцию main(). В main() объявите Barrel для хранения Fedora и еще один Barrel для хранения Loot.
class Barrel<T>(var item: T) fun main(args: Array<String>) { var fedoraBarrel: Barrel<Fedora> = Barrel(Fedora("a generic-looking fedora", 15)) var lootBarrel: Barrel<Loot> = Barrel(Coin(15)) }
Рис.2. Объявление двух Barrel в main() (Variance.kt)
Хотя Barrel<Loot> может хранить награды любого типа, конкретный объявленный экземпляр в примере хранит Coin (подкласс Loot).
Теперь присвойте переменной lootBarrel экземпляр fedoraBarrel.
class Barrel<T>(var item: T) fun main(args: Array<String>) { var fedoraBarrel: Barrel<Fedora> = Barrel(Fedora("a generic-looking fedora", 15)) var lootBarrel: Barrel<Loot> = Barrel(Coin(15)) lootBarrel = fedoraBarrel }
Рис.3. Попытка присвоить значение lootBarrel (Variance.kt)
Удивительно, но эта попытка будет отвергнута компилятором (рисунок 3, несоответствие типа).
Казалось бы, такое присваивание должно быть допустимо. Fedora все-таки является наследником Loot, и переменной типа Loot вполне можно присвоить экземпляр Fedora:
var loot: Loot = Fedora("a generic-looking fedora", 15) // Нет ошибки
Чтобы понять, в чем проблема, давайте поразмышляем, что получится, если такое присваивание выполнится успешно.
Если компилятор разрешит присвоить экземпляр fedoraBarrel переменной lootBarrel, тогда lootBarrel будет указывать на fedoraBarrel и появится возможность взаимодействовать с наградой в fedoraBarrel так, будто это Loot, а не Fedora (потому что тип lootBarrel - это Barrel<Loot>).
Например, монеты - это один из подтипов Loot, поэтому свойству item экземпляра lootBarrel (который указывает на fedoraBarrel) можно было бы присвоить монеты. Сделайте так в Variance.kt.
class Barrel<T>(var item: T) fun main(args: Array<String>) { var fedoraBarrel: Barrel<Fedora> = Barrel(Fedora("a generic-looking fedora", 15)) var lootBarrel: Barrel<Loot> = Barrel(Coin(15)) lootBarrel = fedoraBarrel lootBarrel.item = Coin(15) }
Рис.4. Присваивание монет свойству lootBarrel.item (Variance.kt)
Теперь предположим, что вы обращаетесь к fedoraBarrel.item, ожидая получить шляпу.
class Barrel<T>(var item: T) fun main(args: Array<String>) { var fedoraBarrel: Barrel<Fedora> = Barrel(Fedora("a generic-looking fedora", 15)) var lootBarrel: Barrel<Loot> = Barrel(Coin(15)) lootBarrel = fedoraBarrel lootBarrel.item = Coin(15) val myFedora: Fedora = lootBarrel.item }
Рис.5. Обращение к fedoraBarrel.item (Variance.kt)
Компилятор столкнется с несоотвествием типа - fedoraBarrel.item не Fedora, а Coin, - и вы получите исключение ClassCastException. Теперь у вас возникла проблема, и именно по этой причине компилятор изначально запретил присваивание.
Для решения этой проблемы и были придуманы ключевые слова in и out.
В объявлении класса Barrel добавьте ключевое слово out и измените item c var на val.
class Barrel<out T>(val item: T)
Рис.6. Добавление out (Variance.kt)
Далее удалите строку кода, в которой присваивали Coin свойству item (что теперь запрещено, так как item уже val), и присвойте свойству lootBarrel.item переменную myFedora вместо fedoraBarrel.item.
class Barrel<out T>(val item: T) fun main(args: Array<String>) { var fedoraBarrel: Barrel<Fedora> = Barrel(Fedora("a generic-looking fedora", 15)) var lootBarrel: Barrel<Loot> = Barrel(Coin(15)) lootBarrel = fedoraBarrel val myFedora: Fedora = lootBarrel.item }
Рис.7. Изменение присваивания (Variance.kt)
На следующем шаге мы закончим изучение этого вопроса.