Kotlin中带有接收器的函数文字

时间:2019-01-22 23:16:26

标签: lambda kotlin receiver

我正在根据本教程尝试使用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 :(得分:2)

inc()dec()不会使调用它们的对象发生突变。相反,它们返回该对象的变异副本:

不起作用:

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

作品:

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

答案 1 :(得分:2)

本文作者。您的summer函数的block函数不返回任何内容,您应该将类​​型更改为block: Int.() -> Int,然后返回其响应:

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)
} 

答案 2 :(得分:1)

我认为这是因为dec()是运算符,并且不会修改基础值。 例如,您运行这段代码,应该看到我从未改变,请注意使用val not 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)

}

答案 3 :(得分:1)

您可以在有关operators的文档中找到说明:

  

inc()dec()函数必须返回一个值,该值将分配给使用了++--操作的变量。他们不应更改在其上调用incdec的对象。

从本质上讲,使用如下运算符进行调用:

x++
y--

将根据inc / dec函数进行翻译:

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

奖励发现:在这些函数或运算符上使用意图动作可以使您在两种形式之间进行转换,但这样做是错误的(更改行为,甚至可能破坏编译)。这里有一个未解决的问题。