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

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

Шкодим

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

with, apply, also, run, let

with

Функция 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.

apply

Функция 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

also

Метод для обмена значениями между двумя переменными без участия третьей переменной.


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)

let

let полезен при работе с объектами, которые могут принимать значение null. Вместо того, чтобы создавать длинные цепочки выражений if-else, можно просто скомбинировать оператор ? («оператор безопасного вызова») с let: в результате мы получим лямбду, у которой аргумент it является не nullable-версией исходного объекта.


var cat: String? = null
cat?.let{println(it)} // не выводится
cat = "Barsik"
cat?.let{println(it)}

Второй вариант использования - преобразовать один тип в другой.

run

Узнаем настроение кота.


fun testCat() {
    var mood = "I am sad"

    run {
        val mood = "I am happy"
        println(mood) // I am happy
    }
    println(mood)  // I am sad
}

Logcat:
I/System.out: I am happy
I/System.out: I am sad

В функции дважды используется переменная с одним именем, но они не мешают друг другу и выводят разные сообщения, не переопределяя своих значений.

Это был простейший и достаточно бесполезный пример. В реальности он используется немного иначе.

Реклама