Функции-расширения
Часть раздела Объектно-ориентированное программирование путешествия по Kotlin на Coddy. Урок 30 из 57.
Функция-расширение добавляет функцию к существующему типу, не изменяя исходный код типа. Её имя записывается после типа-получателя, а внутри неё this ссылается на получатель; его также можно не указывать:
fun String.shout() = uppercase() + "!"
fun Int.isEven() = this % 2 == 0Внутри main:
println("hello".shout())
println(7.isEven())
println(listOf(1, 2, 3, 4).count { it.isEven() })Результат:
HELLO!
false
2Расширения работают и с вашими собственными классами, а свойства-расширения добавляют вычисляемые свойства. Расширение не может добавлять хранимое состояние и имеет доступ только к общедоступным членам своего получателя:
class Temperature(val celsius: Double)
val Temperature.fahrenheit: Double
get() = celsius * 9 / 5 + 32
fun Temperature.describe() = "$celsius C is $fahrenheit F"Внутри main:
println(Temperature(100.0).describe())Результат:
100.0 C is 212.0 FРасширения разрешаются статически: объявленный тип выражения выбирает расширение во время компиляции программы, а не класс объекта. Это главное отличие от переопределённого члена:
open class Shape {
open fun member() = "shape member"
}
class Circle : Shape() {
override fun member() = "circle member"
}
fun Shape.ext() = "shape extension"
fun Circle.ext() = "circle extension"Внутри main:
val s: Shape = Circle()
println(s.member())
println(s.ext())Вывод:
circle member
shape extensionЕсли у класса уже есть член с такой же сигнатурой, член всегда имеет приоритет. Используй члены для поведения, относящегося к типу и допускающего переопределение; используй расширения для вспомогательных средств, добавляемых извне, например для форматирования класса, которым ты не владеешь:
class Robot {
fun greet() = "member greet"
}
fun Robot.greet() = "extension greet"
fun Robot.wave() = "extension wave"Внутри main:
val r = Robot()
println(r.greet())
println(r.wave())Вывод:
member greet
extension waveЗадание
ЛегкоMoney(cents) предоставлен в Money.kt. Напишите для него расширения в MoneyExtensions.kt: свойства-расширения Int.dollars и Int.cents, которые преобразуют число в Money (12.dollars — это 1200 центов), Money.format(), который возвращает $12.50 (или -$3.05 для отрицательных сумм), List<Money>.total(), который возвращает сумму как Money, и Money.split(parts), который разделяет сумму на parts частей, отличающихся не более чем на один цент, причём сначала идут большие части.
Предоставленный код считывает строки 12 dollars или 50 cents, а также последнюю строку с количеством частей. Он выводит каждую сумму, total: $12.50 и split 3: $4.17 $4.17 $4.16.
Ваш код должен находиться в MoneyExtensions.kt и Money.kt. В Main.kt находится предоставленный код ввода/вывода, и его нельзя изменять.
Попробуйте сами
fun main() {
// Предоставленный код ввода/вывода: оставьте его как есть
val input = generateSequence(::readLine).toList()
val amounts = input.dropLast(1).map { line ->
val (n, unit) = line.split(" ")
if (unit == "dollars") n.toInt().dollars else n.toInt().cents
}
for (m in amounts) println(m.format())
val total = amounts.total()
println("total: ${total.format()}")
val parts = input.last().toInt()
println("split $parts: " + total.split(parts).joinToString(" ") { it.format() })
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПервичные конструкторыБлоки init и валидацияВторичные конструкторыПовторение — читательский билет4Наследование
Открытые классы и подклассыПереопределение членовsuper и конструкторыАбстрактные классыПовторение — каталог сотрудников7Специальные классы
Классы данныхКлассы перечисленийЗапечатанные иерархииequals, hashCode, toStringПовторение — трекер заказов10Паттерны проектирования. Часть 2
Делегирование с помощью byПаттерн декораторПаттерн строительПаттерн состояние2Свойства и инкапсуляция
Пользовательские аксессорыМодификаторы видимостиПриватные сеттерыlazy и lateinitПовторение — банковский счёт5Интерфейсы
Объявление интерфейсовМетоды по умолчаниюМножественные интерфейсыИнтерфейсы как типыПовторение — способы оплаты8Обобщения
Обобщённые функцииОбобщённые классыОграничения типовВариативность с in и outПовторение — очередь с приоритетом11Проект: Управление библиотекой
Книги и читателиВыдача книг3Объекты и компаньоны
Объявления объектовОбъекты-компаньоныКонстанты с constОбъектные выраженияПовторение — билетная касса6Полиморфизм
Динамическая диспетчеризацияПроверка типов и умные приведения типовwhen с типамиФункции-расширенияПовторение — смотритель зоопарка9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Песочница Kotlin