【问题标题】:Function literal with receiver in KotlinKotlin 中带有接收器的函数字面量
【发布时间】:2019-01-22 23:16:25
【问题描述】:

我正在尝试使用 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'。

谁能提供一些关于如何让这个“简单”示例工作的建议?

【问题讨论】:

  • 我认为是因为 dec() 是一个返回值但不改变对象本身的运算符。

标签: lambda kotlin receiver


【解决方案1】:

本文的作者在这里。您的summer 函数的block 函数没有返回任何内容,您应该将类​​型更改为block: Int.() -&gt; 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】:

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

    不起作用:

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

    作品:

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

    【讨论】:

      【解决方案3】:

      我认为这是因为 dec() 是一个运算符并且不会修改基础值。 例如,您运行此代码,您应该看到 i 永远不会更改,请注意使用 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)
      
      }
      

      【讨论】:

        【解决方案4】:

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

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

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

        x++
        y--
        

        将根据inc/dec 函数转换为:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-03-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多