Kotlin 中带接收者的函数字面量

Function literal with receiver in Kotlin

我正在基于本教程在 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'。

任何人都可以提供一些关于如何使这个 "simple" 示例正常工作的建议吗?

我认为这是因为 dec() 是一个运算符并且不会修改基础值。 例如你 运行 这段代码,你应该看到 i 永远不会改变,注意使用 val 而不是 var,在你的例子中 Idea 应该给你一个提示。 如果将 Int 包装在 class 中,您可以看到带有接收器的函数是如何工作的。

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)

}

你可以在文档中找到关于operators的解释:

The inc() and dec() functions must return a value, which will be assigned to the variable on which the ++ or -- operation was used. They shouldn't mutate the object on which the inc or dec was invoked.

所以本质上,使用这样的运算符进行调用:

x++
y--

根据 inc/dec 函数将被翻译为:

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

额外发现:对这些函数或运算符使用意向操作可以让您在两种形式之间进行转换,但这样做会出错(改变行为,甚至可能破坏编译)。这里有一个未解决的问题。

inc()dec() 不会改变调用它们的对象。相反,他们 return 对象的变异副本:

无效:

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

作品:

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

本文作者在此。您的 summer 函数的 block 函数没有 return 任何东西,您应该将类​​型更改为 block: Int.() -> Int 然后 return 它的响应:

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

现在,您打印的整数将是 4,因为最后一个 dec() 将成为传递的 lambda 的结果。要解决此问题,您可以链接两个 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)
}