串接的結合性 |
|
..
(串接) 和 ^
(指數運算)。^
是右結合對語言來說並不罕見,但 ..
是右結合的則有點不同。在大部分情況下,..
是以右或左結合的運算結果並沒有關係,因為字串的串接是結合性的,但如果要串接的物件有元方法或在串接大量物件時(例如 199 或更多個 - 精確的限制在 luaconf.h 中由 LUAI_MAXCCALLS
決定),然後它的效果就會明顯。..
是右結合而不是 Lua 運算子中常見的左結合,原因主要跟實作的效率有關(請參閱 LuaList:2002-08/msg00218.html 和 LuaList:2002-08/msg00104.html)。一次串接超過大約 199 個元素的問題如下所示。這個 Lua 程式建立一個無法編譯的 Lua 程式。
print([[return 0]] .. ([[ .. 0]]):rep(198))
lua test.lua | luac -p -l - luac: stdin:1: chunk has too many syntax levels
如果我們將 198 減少到 10,我們就能理解原因了。
main <stdin:0,0> (14 instructions, 56 bytes at 0x671200) 0+ params, 11 slots, 0 upvalues, 0 locals, 1 constant, 0 functions 1 [1] LOADK 0 -1 ; "" 2 [1] LOADK 1 -1 ; "" 3 [1] LOADK 2 -1 ; "" 4 [1] LOADK 3 -1 ; "" 5 [1] LOADK 4 -1 ; "" 6 [1] LOADK 5 -1 ; "" 7 [1] LOADK 6 -1 ; "" 8 [1] LOADK 7 -1 ; "" 9 [1] LOADK 8 -1 ; "" 10 [1] LOADK 9 -1 ; "" 11 [1] LOADK 10 -1 ; "" 12 [1] CONCAT 0 0 10 13 [1] RETURN 0 2 14 [1] RETURN 0 1
編譯器會在串接之前將所有常數放入堆疊中。當運算符是 ^
時也會出現同樣錯誤,不過需要對大約 200 個物件進行指數運算的情況可能相當罕見,除非 ^
已使用不同的語意規則覆寫(這可能並非一個好主意)。
不過如果使用左結合運算符(例如加法),則這種程式碼可以正常編譯。
print([[return a]] .. ([[ + a]]):rep(198))
main <stdin:0,0> (399 instructions, 1596 bytes at 0x671200) 0+ params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions 1 [1] GETGLOBAL 0 -1 ; a 2 [1] GETGLOBAL 1 -1 ; a 3 [1] ADD 0 0 1 4 [1] GETGLOBAL 1 -1 ; a 5 [1] ADD 0 0 1 6 [1] GETGLOBAL 1 -1 ; a 7 [1] ADD 0 0 1 ... 390 [1] GETGLOBAL 1 -1 ; a 391 [1] ADD 0 0 1 392 [1] GETGLOBAL 1 -1 ; a 393 [1] ADD 0 0 1 394 [1] GETGLOBAL 1 -1 ; a 395 [1] ADD 0 0 1 396 [1] GETGLOBAL 1 -1 ; a 397 [1] ADD 0 0 1 398 [1] RETURN 0 2 399 [1] RETURN 0 1
物件會被推送到堆疊中並在「[即時]」運行。
__concat
元方法時才會變為可見。如果您實作的 ..
真的是一種串接運算,那它也會是結合性的,但鏈式串接會被分解成 __concat
元方法的成對呼叫,因此您的實作將從右到左呼叫。串接非結合且自然右結合的一個案例是 Posix 正則運算串接;最長相符規則假設相符組元從右到左串接。我不知道這是不是答案:實際的原因可能是它在堆疊機器中實作起來更有效率。--RiciLake
^
作為叉積,但結合性不同。..
將函式裝飾器套用,原因在於 ..
的右結合性。