V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Newyorkcity
V2EX  ›  问与答

为什么 kotlin,或者说一些支持 lambda 表达式的语言,都选择了不允许 lambda 表达式像匿名函数一样直接使用 return?

  •  1
     
  •   Newyorkcity · 2021-07-09 16:10:29 +08:00 · 1600 次点击
    这是一个创建于 1267 天前的主题,其中的信息可能已经有所发展或是发生改变。
    而非要(至少在 kotlin )用上内联之类的概念才可以 return ?

    好像大部分对 lambda 表达式提供原生支持的语言都采取了这样的策略,即在 lambda 表达式中直接使用 return 是被禁止,或者说会直接返回外层函数。为什么要引入这一复杂的机制?就让 lambada 表达式中的 return 和普通的匿名函数一样结束它自己的块不可以吗?
    14 条回复    2021-07-10 13:44:14 +08:00
    xarthur
        1
    xarthur  
       2021-07-09 16:38:50 +08:00 via iPhone
    没怎么看懂问题。
    Kotlin 只是省略吧,你 lambada 最后一行的表达式计算的结果会自动 Return
    Newyorkcity
        2
    Newyorkcity  
    OP
       2021-07-09 16:44:20 +08:00
    @xarthur 显式地裸用 return 关键词在 lambda 表达式中是被禁止的,kotlin 中要用的话其只能作为 inline 函数的参数传入,为什么还有这样的限制。在 lambda 表达式中显式地裸用 return 关键词就直接导致外围函数返回,难道不行吗?

    这次描述不知道清晰了很多没有。。
    TomVista
        3
    TomVista  
       2021-07-09 17:03:37 +08:00
    编译器没办法读懂 无法进行词法语法分析.

    额,直觉,不一定对
    mxalbert1996
        4
    mxalbert1996  
       2021-07-09 17:16:42 +08:00 via Android   ❤️ 1
    感觉你这是两个问题。
    第一,Kotlin 允许在 Lambda 里显式使用 return: https://kotlinlang.org/docs/lambdas.html#returning-a-value-from-a-lambda-expression
    第二,在 lambda 表达式中显式地裸用 return 关键词就直接导致外围函数返回,这当然不可能,因为非 inline 的 lamda 可能在函数 return 以后才被执行。
    Origami404
        5
    Origami404  
       2021-07-09 18:33:14 +08:00 via Android   ❤️ 1
    我也是,有时候会想怎么在一个 lambda 里直接让外层函数返回到外层函数调用者那里去,但是我不知道为什么这样做不可以(虽然好像这样子的话就得像 longjmp 一样搞,因为 lambda 可能被传出去然后在别的地方被调用之后控制流再返回到定义它的那个外层函数那里再返回)
    Leviathann
        6
    Leviathann  
       2021-07-09 18:44:36 +08:00 via iPhone   ❤️ 1
    感觉这样比较好,配合 label 语法多了一种选择,不然的话如果是想直接退出整个函数就要麻烦一些
    Origami404
        7
    Origami404  
       2021-07-09 19:06:01 +08:00 via Android   ❤️ 1
    我跟朋友稍微讨论了一下,觉得这个行为难点主要有:
    1. 析构不好做,控制流乱飞难理解
    2. 可能当这个 lambda 被调用的时候定义它的函数(简称定义函数)跟调用定义函数的函数(简称调用函数)的栈帧都已经被弹出(这种情况可能出现在定义函数将 lambda 整体返回之后调用函数再将其返回直到调用调用函数的函数再调用 lambda )
    3. 我朋友说 λ-expr 应该是无副作用的,而这个很明显是个副作用,所以哲学上不对味... (当然考虑 C++的 lambda 使用引用捕获外部变量再修改的情况可以得知其实存在有语言的 lambda 是可以有副作用的)

    这种行为的实现方式我大概想了一下,可能使用 c++搭配 setjmp 跟 longjmp 可以实现,但是不一定能完美实现(可能会有一些对象的生命周期问题)。

    如果能够完美实现的话其实还是有一定用处的,比如可以拿这种行为来实现整个程序级的“时间倒流”(做法类似于我上面提到的在上层函数调用下层函数定义的带 return 的 lambda )(就像 Vue 的调试工具那种)

    随便想想,可能会有不足,欢迎大家指正
    Origami404
        8
    Origami404  
       2021-07-09 19:07:02 +08:00 via Android
    另外以我半吊子的 lisp 水平不知道 lisp 里的 call/cc 能否实现这种行为?
    agagega
        9
    agagega  
       2021-07-09 19:29:26 +08:00 via iPhone
    Ruby 可以,在 block 里的 return 指的是 return 外层的函数。不过 Ruby 连 call/cc 都有,倒也算某种 lisp 了…
    @Origami404
    billlee
        10
    billlee  
       2021-07-09 20:36:28 +08:00
    应该是函数式语言中,只有表达式,没有控制结构。纯粹的函数式语言没有循环只有递归,没有条件语句,只有条件表达式,所以自然也不会增加一个 return 控制结构。
    xarthur
        11
    xarthur  
       2021-07-09 23:11:23 +08:00 via iPhone
    @Origami404 你想要的东西是 CPS 变换?
    xarthur
        12
    xarthur  
       2021-07-09 23:15:54 +08:00 via iPhone   ❤️ 1
    @Newyorkcity 因为 lambda 的作用域是不一样的啊,如果你在 lambda 里写 return 返回上层函数作用域就全乱了。
    至于为什么要省略 return,应该和 kotlin dsl 语法糖的设计有关,想象一个函数,唯一的参数就是闭包,那么你把闭包提出来,省略掉圆括号,剩下的部分就基本上可以像写配置文件一样写业务逻辑了,配置文件中突然冒出一个 return 有点怪怪的。
    (不过我也觉得,不应该强迫程序员一定要省略 return,不过 kotlin 就是这么设计的也没什么办法)。
    Jirajine
        13
    Jirajine  
       2021-07-10 08:12:45 +08:00 via Android
    lambda 直接 inline,return 能直接结束外层函数这种特性多好。可惜很多语言没有,为了返回错误之类的,只能把 map 改成循环。
    ccde8259
        14
    ccde8259  
       2021-07-10 13:44:14 +08:00 via iPhone
    对于在 A 对象的 a 方法中声明了一个实现了 Runnable 的 lambda 的 B 对象情况下,B 对象可能被引用传递给 C 对象后在 c 方法中执行了 B.run()……
    此时 B 对象内的 return 不可能把 a 方法 return 掉。其次是把 c 方法 return 掉的时候整个控制流程就脱离了 c 方法的控制。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2849 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 06:14 · PVG 14:14 · LAX 22:14 · JFK 01:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.