例如上述代码中,第一个 it 去了 async 的默认参数,而 第二个 it 使用了 forEach 的默认参数
1
sorra 2017-11-24 18:19:26 +08:00
当然是取最近的。
你这个奇怪,可能是根据用法自动匹配了不同类型的 it,但这不合理,应该报编译错误才是编译器的合理设计。 对开发者来说,这里要给参数命名,不应该使用 it。 |
2
jinyang656 2017-11-24 19:06:06 +08:00
这编译器不报错咩,神奇
|
3
DeweyReed 2017-11-24 19:26:43 +08:00
一般为了可读性都会重命名
list.forEach{ item -> ... } |
4
twoyuan OP @sorra #1 确实是应该有 warning 才合理一些,第一个 it 匹配到了带有 invoke 的 async 默认参数可以理解,第二个在两个 it 都有 toString 的情况下却匹配了正确的,让人觉得可怕……
|
5
sagaxu 2017-11-24 21:39:25 +08:00
|
6
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
|
7
SoloCompany 2017-11-24 22:28:38 +08:00 via iPhone
async block 哪来的输入参数,明明是 ()->?
|
8
twoyuan OP |
9
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) } } } } ``` |
10
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") } } } |
11
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 工具来解决了。 |
12
SoloCompany 2017-11-26 15:18:09 +08:00 via iPhone
@sorra 这根本是两个问题好吗,请看我给出的例子,这个问题和 it 变量没有关系,只是类型推断系统过于智能是否合适的问题而已
|
13
sorra 2017-11-26 16:30:59 +08:00
帖子里讨论了嵌套 Lambda 的问题,对于重定义的 it 不报任何警告是危险的。显式的参数没那么危险。
Java 的做法是禁止 Lambda 重定义局部变量。用匿名内部类就没有这个限制。 题外话,Java 只允许 final 变量提升到闭包作用域,而 Scala/Kotlin 允许 var。 这方面个人认为还是 Java 更严谨。 |
14
SoloCompany 2017-11-29 14:09:44 +08:00
@sorra #13 重名的问题的确 error 比 warning 更合适, 不过有 lint 工具的话这个也不是什么大问题; 反而 mutable 变量不能在闭包中使用这一点我绝对认为 kotlin 的做法(当然只是 sugar) 更合理, 在没有更好选择的前提下为此写一个 wrapper 的做法简直就像破补丁一样太不优雅了
|