使用lambda参数进行方法链接的惯例是什么?

时间:2018-02-05 16:27:56

标签: lambda kotlin

我正在进行Kotlin编码挑战,我提出了一个看起来像这样的解决方案:

val x = listOf(1, 2, 3)
    .fold("") { acc, i ->
      acc + someLookupFunction(i)
    }.let {
      // something
    }

以上是我希望它的格式化方式。但是,在使用IntelliJ自动格式化程序时,它坚持要将代码格式化为:

val x = listOf(1, 2, 3)
    .fold("") { acc, i ->
      acc + someLookupFunction(i)
    }.let {
          // something
        }

我的第一个想法是,这是一个错误,但实际上我认为它只是模棱两可。格式化程序必须认为let是对lambda本身的函数调用,而不是fold的结果。为了证实这一点,我将其更改为:

val x = listOf(1, 2, 3)
    .fold("", { acc, i ->
      acc + someLookupFunction(i)
    }).let {
      // something
    }

和Intellij格式化了我的期望。所以这让我想到了一个问题 - 在使用像这样的lambdas时是否存在关于链接方法调用的官方约定?链接时我应该使用明确的parens以避免歧义吗?这实际上是我应该报告的Intellij的错误吗?

2 个答案:

答案 0 :(得分:2)

Kotlin文档中有一节关于编码样式,包括this on chained-call wrapping

  

链式呼叫包装

     

当包裹链式呼叫时,请将其放入。性格还是?下一行的运算符,只有一个缩进:

val anchor = owner
    ?.firstChild!!
    .siblings(forward = true)
    .dropWhile { it is PsiComment || it is PsiWhiteSpace }
     

链中的第一个调用通常应该在它之前有一个换行符,但是可以省略它,代码更有意义。

所以我可能会改变它:

  val x = listOf(1, 2, 3)
      .fold("") { acc, i ->
          acc + someLookupFunction(i)
      }
      .let {
          // something
      }

或者:

val x = listOf(1, 2, 3)
    .fold("") { acc, i -> acc + someLookupFunction(i) }
    .let { /* something */ }

答案 1 :(得分:1)

IntelliJ建议的格式是正确的,因为当lambda是函数的最后一个参数时,lambda可以从方法的括号中提取出来。

因此,IntelliJ不认为let是对lambda本身的函数调用,它只是编写与您期望的相同代码的另一种方式(您的第3个代码段)。

来自Kotlin official documentation

  

在Kotlin中,有一个约定,如果函数的最后一个参数是一个函数,并且您将lambda表达式作为相应的参数传递,则可以在括号外指定它。 [...]这些约定允许编写LINQ样式的代码:

     

strings.filter { it.length == 5 }.sortedBy { it }.map { it.toUpperCase() }