我正在进行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的错误吗?
答案 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() }