为什么在Lua中,表字面量与表引用会被不同地处理?

以下是Lua 5.2.2的记录,显示了一个表的声明和索引:

> mylist = {'foo', 'bar'}
> print(mylist[1])
foo

为什么以下语句不合法?

> print({'foo', 'bar'}[1])
stdin:1: ')' expected near '['

我想不到还有其他语言中文字面量不能替换引用(当然,除非需要lvalue)。

FWIW,将表的文字用括号括起来就可以使语句合法:

> print(({'foo', 'bar'})[1])
foo
点赞
用户2303714
用户2303714

根据 这里 定义的语法规则,非括号版本无效而括号版本有效的原因是因为语法树采用了不同的路径,期望有一个关闭括号 ),因为在那个上下文中 应该 没有其他符号。

在第一个案例中:

functioncall ::=  prefixexp args | prefixexp `:´ Name args

    prefixexp =>
        prefixexp ::= var | functioncall | `(´ exp `)´

            var -> print
    因此 prefixexp -> print

    args =>
        args ::=  `(´ [explist] `)´ | tableconstructor | String
            匹配 '('

            explist =>
                explist ::= {exp `,´} exp
                    exp =>
                        exp ::=  nil | false | true | Number | String | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp
                            tableconstructor =>
                    explist-> {'foo','bar'}

            因此 explist = {'foo','bar'}

            匹配 ')' 错误!!!发现 '[' 预期 ')'

另一方面,使用括号:

functioncall ::=  prefixexp args | prefixexp `:´ Name args

    prefixexp =>
        prefixexp ::= var | functioncall | `(´ exp `)´

            var -> print
    因此 prefixexp -> print

    args =>
        args ::=  `(´ [explist] `)´ | tableconstructor | String
            匹配 '('

            explist =>
                explist ::= {exp `,´} exp
                    exp =>
                        exp ::=  nil | false | true | Number | String | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp
                            prefixexp =>
                                prefixexp ::= var | functioncall | `(´ exp `)´
                                    var =>
                                        var ::=  Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name
                                            prefixexp =>
                                                prefixexp ::= var | functioncall | `(´ exp `)´
                                                匹配 '('
                                                exp =>
                                                    exp ::=  nil | false | true | Number | String | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp
                                                    tableconstructor =>
                                                因此 exp = {'foo','bar'}
                                                匹配 ')'
                                            因此 prefixexp = ({'foo','bar'})
                                            匹配 '['
                                            exp => Number = 1
                                            匹配 ']'
                                    因此 VAR = ({'foo','bar'})[1]
                            因此 prefixexp = VAR
                    因此 exp = VAR
            因此 explist = VAR
            匹配 ')'
    因此 args = (VAR)
=> print(VAR)
2013-10-12 07:27:35
用户2633423
用户2633423

这也与 Lua 中这种语法是有效的事实相关:

myfunc { 1, 2, 3 }

等同于:

myfunc( { 1, 2, 3 } )

因此,例如此表达式:

myfunc { 1, 2, 3 } [2]

被解析为:

myfunc( { 1, 2, 3 } )[2]

因此,首先计算函数调用,然后进行索引操作。

如果 {1,2,3}[2] 可被解析为有效的索引操作,它可能会导致前面式子中的歧义情况,需要更多的前瞻。Lua 团队选择通过让 Lua 字节码编译器成为一次单独的编译器,使其快速扫描源代码,只需最少的前瞻。该信息来源于 Lua 开发者 Roberto Ierusalimschy 的邮件列表信息。

字符串文本和方法调用也存在同样的问题。这是无效的:

"my literal":sub(1)

但是这是有效的:

("my literal"):sub(1)

同样,Lua 允许这种操作:

func "my literal"

等同于:

func( "my literal" )
2013-10-12 08:39:35