Освой Kotlin играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Функции-расширения (Extension functions)

Java содержит множество классов с замечательными методами. Но разработчику всегда не хватает ещё одного метода, который ему нужен для собственного проекта. Функции-расширения позволяют создавать видимость внедрения в существующий класс нового метода. Это позволяет более элегантно решить проблему с классами Utils, которые создают разработчики для подобных целей. Кроме того, созданные функции будут выводиться в подсказках при наборе кода вместе с стандартными методами класса.

Рассмотрим пример на Java. Как узнать, является ли указанная дата субкотой (иногда люди используют слово "суббота")? У класса Date нет соответствующего метода и мы можем определить субботу только по методу getDay(), который возвращает число 6 для субботы.

Создадим класс Utils.java и поместим свой метод.


static boolean isSaturday(Date date) {
	return date.getDay() == 6;
}

Вызываем метод по щелчку кнопки.


public void onClick(View view) {
    Date now = new Date();
    boolean saturday = Utils.isSaturday(now);
    mInfoTextView.setText("Сегодня субкота? " + saturday);
}

Теперь рассмотрим, как это можно сделать на Kotlin.

Добавим функцию в активность и вызовем её по щелчку кнопки.


fun Date.isSaturday(): Boolean {
    return getDay() == 6
}

button_choose.setOnClickListener {
    val now = Date()
    val saturday = now.isSaturday()
    textview_info.text = "Сегодня субкота?  + $saturday"
}

Теперь, если смотреть на код, то создаётся ощущение, что isSaturday() является частью класса Date и мы вызываем его прямо из класса.

Предыдущий пример с функцией был написан в Java-стиле. В Kotlin можно заменить метод getDay() на свойство day.


fun Date.isSaturday(): Boolean {
	return day == 6
}

Впрочем и это не предел. Подобную функцию можно переписать в одну строку.


fun Date.isSaturday(): Boolean = day == 6

Если у вас будет несколько подобных функций-расширений, то удобнее их хранить в отдельном файле (не обязательно в классе). Создадим дополнительный пакет utils с файлом Utils.kt.


package ru.alexanderklimov.counter.utils

import java.util.*

fun Date.isSaturday() = day == 6

// другие функции-расширения

В активности при вызове функции следует импортировать её (возможно это сделает сама студия автоматически).


import ru.alexanderklimov.counter.utils.isSaturday

// код для кнопки останется прежним

Можно переопределить имя функции при помощи as:


import ru.alexanderklimov.counter.utils.isSaturday as caturday

val saturday = now.caturday()

Другие примеры из различных докладов и презентаций.

Функция для получения последнего символа из строки.


fun String.lastChar() = get(length - 1)

// Применяем к строке
val cat = "Мурзик"
val c: Char = cat.lastChar()
textview_info.text = cat.lastChar().toString() // длинный вариант

Знакомый нам пример. Мы добавляем в класс Context новую функцию toast(), которая вызывает метод Toast.makeText() с использованием параметров по умолчанию.


fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, message, duration).show()
}

// вызываем в активности
toast("Hello Kitty")

JetBrains добавила свой набор расширений для различных классов Java и Android. Самый показательный случай - набор расширений для коллекций - функции filter(), map(), count() и т.д. в функциональном стиле, даже используя старую Java 6.

Помните, что функции-расширения класса не могут обращаться к его членам с модификаторами protected или private.

Ключевое слово inflix

Если ваша функция-расширение использует только один аргумент, то можно вызвать функцию через ключевое слово infix.

Создадим функцию-расширение для Int, которое будет сравнивать число с аргументом, чтобы узнать, больше оно или меньше.

Старый способ.


fun Int.isGreater(value: Int): Boolean {
    return this > value
}

// вызываем функцию
3.isGreater(9) // false

Перепишем функцию с ключевым словом infix.


infix fun Int.isGreater(value: Int): Boolean {
    return this > value
}

// вызываем функцию
12 isGreater 9 // true

Дополнительное чтение

Android Development with Kotlin — Jake Wharton - YouTube - несколько примеров, начиная с 12.20 до 15.50

Реклама