Освой Kotlin играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
В Kotlin есть пять функций, которые обозначаются как диапазонные функции. Смысл диапазонной функции заключается в том, чтобы брать существующий объект и представлять его определённым образом в этом новом диапазоне.
Функция with позволяет выполнить несколько операций над одним объектом, не повторяя его имени.
Функция принимает два аргумента - объект и лямбда-выражение. Первый аргумент преобразуется в получатель лямбда-выражения. К получателю можно обращаться через this.
class Cat{
var name:String? = null
var breed:String? = null
}
val murzik = Cat()
murzik.name = "Murzik"
// Вместо
val murzikName = murzik.name
val murzikBreed = murzik.breed
println("$murzikName:$murzikBreed")
// Укороченный вариант с лямбдой
with(murzik){
val murzikName = name
val murzikBreed = breed
println("$murzikName:$murzikBreed")
}
Нам уже не нужно каждый раз упоминать имя объекта.
Ещё один пример посложнее.
// выводим все буквы алфавита
fun printAlphabet() = with(StringBuilder()){
for (letter in 'A'..'Z'){
append(letter)
}
toString()
}
println(printAlphabet()) // ABCDEFGHIJKLMNOPQRSTUVWXYZ
Функция возвращает результат последнего выражения в теле лямбда-выражения. Если вам нужен объект-получатель, то используйте apply.
Диапазонная функция run() работает так же, как и функция with(), но это не обычная функция верхнего уровня, а функция-расширение и её нужно вызывать с помощью точечной нотации.
class Cat{
var name:String? = null
var breed:String? = null
}
val murzik = Cat()
murzik.run {
name = "Мурзик"
breed = "Невская маскарадная"
}
println(murzik.name)
println(murzik.breed)
let полезен при работе с объектами, которые могут принимать значение null. Вместо того, чтобы создавать длинные цепочки выражений if-else, можно просто скомбинировать оператор ? («оператор безопасного вызова») с let: в результате мы получим лямбду, у которой аргумент it является не nullable-версией исходного объекта.
var cat: String? = null
cat?.let{println(it)} // не выводится
cat = "Barsik"
cat?.let{println(it)}
Функция apply работает почти так же, как with, но возвращает объект, переданный в аргументе.
fun printAlphabet() = StringBuilder().apply{
for (letter in 'A'..'Z'){
append(letter)
}
}.toString()
println(printAlphabet())// ABCDEFGHIJKLMNOPQRSTUVWXYZ
Полезна в тех случаях, когда требуется создание экземпляра, у которого следует инициализировать некоторые свойства. Часто в этих случаях мы просто повторяем имя экземпляра.
val button = findViewById<Button>(R.id.button)
button.text = "I am a button"
button.textSize = 18.0F
button.setBackgroundColor(Color.RED)
Инициализируем настройки кнопки через apply.
val button = findViewById<Button>(R.id.button)
button.apply{
text = "I am a button"
textSize = 18.0F
setBackgroundColor(Color.RED)
}
Применим к коту, поменяв возраст.
class Cat(var age: Int)
val result = Cat(5).apply { age = 8 }
println(result.age) // 8
Метод для обмена значениями между двумя переменными без участия третьей переменной.
var x = 100
var y = 25
x = y.also { y = x }
println(x)
println(y)
class Cat(var age: Int)
val result = Cat(5).also { it.age = 8 }
println(result.age) // 8
Склеиваем строки.
val game: String = StringBuilder().also {
it.append("tic")
it.append("tac")
it.append("toe")
}
.toString()
println(game)