Kotlin 编译器如何判断在嵌套 Lambda 中应该取哪个默认参数 it?

2017-11-24 17:55:52 +08:00
 twoyuan

例如上述代码中,第一个 it 去了 async 的默认参数,而 第二个 it 使用了 forEach 的默认参数

8408 次点击
所在节点    Kotlin
14 条回复
sorra
2017-11-24 18:19:26 +08:00
当然是取最近的。
你这个奇怪,可能是根据用法自动匹配了不同类型的 it,但这不合理,应该报编译错误才是编译器的合理设计。
对开发者来说,这里要给参数命名,不应该使用 it。
jinyang656
2017-11-24 19:06:06 +08:00
这编译器不报错咩,神奇
DeweyReed
2017-11-24 19:26:43 +08:00
一般为了可读性都会重命名
list.forEach{ item -> ... }
twoyuan
2017-11-24 21:28:08 +08:00
@sorra #1 确实是应该有 warning 才合理一些,第一个 it 匹配到了带有 invoke 的 async 默认参数可以理解,第二个在两个 it 都有 toString 的情况下却匹配了正确的,让人觉得可怕……
sagaxu
2017-11-24 21:39:25 +08:00
sagaxu
2017-11-24 21:40:20 +08:00
Expression 'it' of type 'Int' cannot be invoked as a function. The function 'invoke()' is not found
SoloCompany
2017-11-24 22:28:38 +08:00
async block 哪来的输入参数,明明是 ()->?
twoyuan
2017-11-24 23:13:23 +08:00
@sagaxu #6
@SoloCompany #7

抱歉,async 是我自己随便封装的一个函数,忘了协程好像也有这个 😂
sorra
2017-11-25 10:37:45 +08:00
属实,测试代码如下,可怕。谁去给官方报个 issue 啊
```

fun sync(f: ((() -> Unit) -> Unit) -> Unit) {
f {
it()
}
}

fun main(args: Array<String>) {
sync {
it {}
(1..10).forEach {
it {
println(it)
}
}
}
}

```
SoloCompany
2017-11-25 19:49:43 +08:00
@twoyuan 很正常, type inference 有时候因为过于智能会显得比较魔幻

执行一下
fun main(args: Array<String>) = run { val run = 1; run { print("run: $run") } }

或者甚至 (后面这个会有个编译警告, 但警告的也仅仅是变量重名而不是 type inference 混淆)
fun main(args: Array<String>) {
val x: (() -> Any) -> Any = ::run;
x { val x = 1; x { print("x: $x") } }
}
sorra
2017-11-26 11:37:02 +08:00
@jinyang656 @SoloCompany @sagaxu
https://discuss.kotlinlang.org/t/will-it-variable-stay-or-go/522/8
2014 年有讨论,但直到 1.0 发布都没结论,于是为了兼容性而搁置了问题。
大概只能用 Lint 工具来解决了。
SoloCompany
2017-11-26 15:18:09 +08:00
@sorra 这根本是两个问题好吗,请看我给出的例子,这个问题和 it 变量没有关系,只是类型推断系统过于智能是否合适的问题而已
sorra
2017-11-26 16:30:59 +08:00
帖子里讨论了嵌套 Lambda 的问题,对于重定义的 it 不报任何警告是危险的。显式的参数没那么危险。
Java 的做法是禁止 Lambda 重定义局部变量。用匿名内部类就没有这个限制。

题外话,Java 只允许 final 变量提升到闭包作用域,而 Scala/Kotlin 允许 var。

这方面个人认为还是 Java 更严谨。
SoloCompany
2017-11-29 14:09:44 +08:00
@sorra #13 重名的问题的确 error 比 warning 更合适, 不过有 lint 工具的话这个也不是什么大问题; 反而 mutable 变量不能在闭包中使用这一点我绝对认为 kotlin 的做法(当然只是 sugar) 更合理, 在没有更好选择的前提下为此写一个 wrapper 的做法简直就像破补丁一样太不优雅了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/409298

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX