为什么Lua表达式中没有匿名函数?
有人能解释一下为什么Lua中的匿名函数构造不是一个完整的表达式吗?对我来说,这似乎是一种怪异的情况:它(稍微)违反了函数应该成为一等公民对象的想法,并且(虽然不经常但有时)是一个不方便的问题,在大多数情况下,这是一个真正经过深思熟虑且优雅的语言。
例如,使用命令行Lua,可以绕过此问题
Lua 5.3.3 版权所有(C) 1994-2016 Lua.org, PUC-Rio
> function(x) return x*x end (2)
stdin:1: <name> expected near '('
> square = function(x) return x*x end
> square(2)
4
简短回答
调用一个函数,函数表达式必须是一个名称、一个索引值、另一个函数调用,或者在括号内的表达式。
长回答
我不知道为什么它被设计成这样,但我查了语法,看看它是如何工作的。这里是一个函数调用的部分:
functioncall ::= prefixexp args | prefixexp ‘:’ Name args
"args" 就是括号中的参数列表。相关的部分是 "prefixexp"。
prefixexp ::= var | functioncall | ‘(’ exp ‘)’
Okay,所以我们可以调用另一个 "functioncall","exp" 就是普通的表达式:
exp ::= nil | false | true | Numeral | LiteralString | ‘...’ | functiondef | prefixexp | tableconstructor | exp binop exp | unop exp
所以我们可以调用任何表达式,只要它在括号内。"functiondef" 涵盖匿名函数:
functiondef ::= function funcbody
funcbody ::= ‘(’ [parlist] ‘)’ block end
所以一个匿名函数是一个 "exp",但不是一个 "prefixexp",所以我们需要在它周围加上括号。
什么是 "var"?
var ::= Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name
"var" 是一个名称或一个索引值(通常是一个表)。注意,索引值必须是一个 "prefixexp",这意味着字符串文字或表构造必须在索引之前用括号括起来。
总而言之:被调用的函数必须是一个名称、一个索引值、一个函数调用,或者在括号内的其他表达式。
最大的问题是:为什么 "prefixexp" 与 "exp" 处理不同?我不知道。我怀疑它与将函数调用和索引保持在常规的运算符优先级之外有关,但我不知道这是为什么必要的。
Lua的函数调用语法内置了一些语法糖。你可以用三种方法调用函数:
- 带括号的值列表。
- 表构造函数(函数将作为一个单一的参数取表)。
- 字符串字面量。
Lua希望它的语法规则相对规律。因此,如果有一种你可以用这些方法之一调用的东西,那么在任何这些方法中调用它都应该是有意义的。
考虑以下代码:
local value = function(args)
--does some stuff
end "I'm a literal" .. foo
如果我们允许任意的、非括号表达式像其他函数调用一样被调用,那么这意味着创建一个函数,使用字符串字面量调用它,并将该函数调用的结果与foo连接起来,然后将其存储在value中。
但是……我们真的想要这个工作吗?也就是说,我们希望人们能够写出这种代码并使其成为有效的Lua代码吗?
如果这样的代码被认为是不美观或混乱的,那么就有几种选择。
- Lua可以没有带有字符串字面量的函数调用。毕竟,你只需要节省2个括号。甚至也可以不允许表构造函数,虽然它们不太不美观也不太混乱。让所有人都用括号来进行所有函数调用。
- Lua可以使只有在使用lambda的情况下才防止使用字符串字面量进行函数调用。这将需要实质性地改变语法规则。
- Lua可以强制您括起任何在调用函数不是前面文本的显然意图的结构中。
现在,有人可能会争论说table_name[var_name] "literal"已经相当混乱了。但再次防止特定的行为将需要改变语法规则。你必须添加所有这些特殊情况,例如name "literal"是函数调用,但name.name "literal"不是。因此,选项2就被排除了。
使用字符串字面量调用函数的能力不只是限于Lua。JavaScript可以做到,不过你必须使用特定的文字语法才能做到。此外,能够输入require "module_name"感觉像是一个好主意。由于这样的调用被认为是一种重要的语法糖,被几种语言支持,所以选项#1被排除了。
因此您唯一的选择是选项3:使人们用括号括起他们想要调用的表达式。
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

我明白了...需要使用圆括号,抱歉。
(function(x) return x*x end) (2)我仍然不明白为什么要设计成那样。