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

2021-07-09 16:10:29 +08:00
 Newyorkcity
而非要(至少在 kotlin )用上内联之类的概念才可以 return ?

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

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

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

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

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

随便想想,可能会有不足,欢迎大家指正
Origami404
2021-07-09 19:07:02 +08:00
另外以我半吊子的 lisp 水平不知道 lisp 里的 call/cc 能否实现这种行为?
agagega
2021-07-09 19:29:26 +08:00
Ruby 可以,在 block 里的 return 指的是 return 外层的函数。不过 Ruby 连 call/cc 都有,倒也算某种 lisp 了…
@Origami404
billlee
2021-07-09 20:36:28 +08:00
应该是函数式语言中,只有表达式,没有控制结构。纯粹的函数式语言没有循环只有递归,没有条件语句,只有条件表达式,所以自然也不会增加一个 return 控制结构。
xarthur
2021-07-09 23:11:23 +08:00
@Origami404 你想要的东西是 CPS 变换?
xarthur
2021-07-09 23:15:54 +08:00
@Newyorkcity 因为 lambda 的作用域是不一样的啊,如果你在 lambda 里写 return 返回上层函数作用域就全乱了。
至于为什么要省略 return,应该和 kotlin dsl 语法糖的设计有关,想象一个函数,唯一的参数就是闭包,那么你把闭包提出来,省略掉圆括号,剩下的部分就基本上可以像写配置文件一样写业务逻辑了,配置文件中突然冒出一个 return 有点怪怪的。
(不过我也觉得,不应该强迫程序员一定要省略 return,不过 kotlin 就是这么设计的也没什么办法)。
Jirajine
2021-07-10 08:12:45 +08:00
lambda 直接 inline,return 能直接结束外层函数这种特性多好。可惜很多语言没有,为了返回错误之类的,只能把 map 改成循环。
ccde8259
2021-07-10 13:44:14 +08:00
对于在 A 对象的 a 方法中声明了一个实现了 Runnable 的 lambda 的 B 对象情况下,B 对象可能被引用传递给 C 对象后在 c 方法中执行了 B.run()……
此时 B 对象内的 return 不可能把 a 方法 return 掉。其次是把 c 方法 return 掉的时候整个控制流程就脱离了 c 方法的控制。

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

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

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

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

© 2021 V2EX