Функция литерал с приемником в Котлине - PullRequest
0 голосов
/ 23 января 2019

Я пытаюсь использовать литерал функции с примером получателя в kotlin, основанном на этом уроке: https://kotlinexpertise.com/coping-with-kotlins-scope-functions/

Я ожидаю получить 3 обратно из кода ниже, но, похоже, метод Int dec() не выполняется или переменная «mint» не обновляется.

fun summer(block: Int.() -> Unit): Int{
     var myint = 5
    myint.block()
    return myint
    }
fun main(args: Array<String>) {
    var mint = summer{
        dec()
        dec()
     }
    println(mint)
}

Вывод здесь - «5».

Может кто-нибудь предложить несколько советов о том, как получить это«простой» пример работает?

Ответы [ 4 ]

0 голосов
/ 23 января 2019

Автор этой статьи здесь. Функция block вашей summer функции ничего не возвращает, вы должны изменить тип на block: Int.() -> Int и затем вернуть его ответ:

fun summer(block: Int.() -> Int): Int {
    val myint = 5
    return myint.block()
}

Теперь ваше напечатанное целое число будет 4, потому что последнее dec() станет результатом пройденной лямбды. Чтобы это исправить, вы можете связать оба dec звонка:

fun main(args: Array<String>) {
    val mint = summer {
        dec().dec()
    }
    println(mint)
}

Наконец, 5 будет уменьшен вдвое, что приведет к 3.

Если, с другой стороны, у вас есть какой-то произвольный объект, который мутирует с помощью функции dec, ваш подход будет работать так:

class Ref(var v: Int) {
    fun dec() {
        v -= 1
    }
}

fun summer(block: Ref.() -> Unit): Int {
    val ref = Ref(5).apply(block)
    return ref.v
}

fun main(args: Array<String>) {
    val mint = summer {
        dec()
        dec()
    }
    println(mint)
} 
0 голосов
/ 23 января 2019

Вы можете найти объяснение в документации о операторах :

Функции inc() и dec() должны возвращать значение, которое будет присвоено переменнойна котором использовалась операция ++ или --.Они не должны видоизменять объект, для которого был вызван inc или dec.

По сути, вызовы с использованием таких операторов:

x++
y--

будутв переводе на это в терминах функций inc / dec:

x = x.inc()
y = y.dec()

Поиск бонуса: использование намеренных действий над этими функциями или операторами позволяет вам конвертировать между двумя формами, но делает этоошибочно (меняет поведение, может даже нарушить компиляцию).Здесь есть проблема, открытая для этого.

0 голосов
/ 23 января 2019

inc() и dec() не изменяют объект, на который они вызваны.Вместо этого они возвращают видоизмененную копию объекта:

Не работает:

var a = 5
a.inc()
println(a) // 5

Работает:

var a = 5
a = a.inc()
println(a) // 6
0 голосов
/ 23 января 2019

Я думаю, это потому, что dec () является оператором и не изменяет базовое значение.Например, если вы запускаете этот код, вы должны видеть, что я никогда не меняюсь, обратите внимание на использование val, а не var, в вашем примере Idea должна дать вам подсказку.Если вы поместите Int в класс, вы увидите, как работает функция с приемником.

data class Foo(var i:Int) {
    fun dec() {
        i = i.dec()
    }
}


fun summer(block: Foo.() -> Unit): Foo{
    val myint = Foo(5)
    myint.block()
    return myint


}

fun main(args: Array<String>) {

    val i = 42
    println("i = $i")  // i = 42
    val j = i.dec()   
    println("j = $j")  // i = 41
    println("i = $i")  // i = 42

    val x = summer {
        dec()
        dec()
    }
    println(x)  // Foo(i=3)

}
...