twoyuan
V2EX  ›  Kotlin

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

  •  
  •   twoyuan · Nov 24, 2017 · 9167 views
    This topic created in 3101 days ago, the information mentioned may be changed or developed.

    code

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

    14 replies    2017-11-29 14:09:44 +08:00
    sorra
        1
    sorra  
       Nov 24, 2017
    当然是取最近的。
    你这个奇怪,可能是根据用法自动匹配了不同类型的 it,但这不合理,应该报编译错误才是编译器的合理设计。
    对开发者来说,这里要给参数命名,不应该使用 it。
    yufz
        2
    yufz  
       Nov 24, 2017
    这编译器不报错咩,神奇
    DeweyReed
        3
    DeweyReed  
       Nov 24, 2017
    一般为了可读性都会重命名
    list.forEach{ item -> ... }
    twoyuan
        4
    twoyuan  
    OP
       Nov 24, 2017
    @sorra #1 确实是应该有 warning 才合理一些,第一个 it 匹配到了带有 invoke 的 async 默认参数可以理解,第二个在两个 it 都有 toString 的情况下却匹配了正确的,让人觉得可怕……
    sagaxu
        5
    sagaxu  
       Nov 24, 2017
    sagaxu
        6
    sagaxu  
       Nov 24, 2017
    Expression 'it' of type 'Int' cannot be invoked as a function. The function 'invoke()' is not found
    SoloCompany
        7
    SoloCompany  
       Nov 24, 2017 via iPhone
    async block 哪来的输入参数,明明是 ()->?
    twoyuan
        8
    twoyuan  
    OP
       Nov 24, 2017
    @sagaxu #6
    @SoloCompany #7

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

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

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

    ```
    SoloCompany
        10
    SoloCompany  
       Nov 25, 2017
    @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
        11
    sorra  
       Nov 26, 2017
    @jinyang656 @SoloCompany @sagaxu
    https://discuss.kotlinlang.org/t/will-it-variable-stay-or-go/522/8
    2014 年有讨论,但直到 1.0 发布都没结论,于是为了兼容性而搁置了问题。
    大概只能用 Lint 工具来解决了。
    SoloCompany
        12
    SoloCompany  
       Nov 26, 2017 via iPhone
    @sorra 这根本是两个问题好吗,请看我给出的例子,这个问题和 it 变量没有关系,只是类型推断系统过于智能是否合适的问题而已
    sorra
        13
    sorra  
       Nov 26, 2017
    帖子里讨论了嵌套 Lambda 的问题,对于重定义的 it 不报任何警告是危险的。显式的参数没那么危险。
    Java 的做法是禁止 Lambda 重定义局部变量。用匿名内部类就没有这个限制。

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

    这方面个人认为还是 Java 更严谨。
    SoloCompany
        14
    SoloCompany  
       Nov 29, 2017
    @sorra #13 重名的问题的确 error 比 warning 更合适, 不过有 lint 工具的话这个也不是什么大问题; 反而 mutable 变量不能在闭包中使用这一点我绝对认为 kotlin 的做法(当然只是 sugar) 更合理, 在没有更好选择的前提下为此写一个 wrapper 的做法简直就像破补丁一样太不优雅了
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   945 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 21:47 · PVG 05:47 · LAX 14:47 · JFK 17:47
    ♥ Do have faith in what you're doing.