进服务器出现too many linksua is errors,sorry,怎么破

lua-users wiki: Switch Statement
The problem
Lua lacks a C-style switch statement.
This issue has come up a number of times on the mailing list.
There are ways to emulate the same effect as discussed here.
The first question to ask is why we might want a switch statement rather than a comparison chain as such:
local is_canadian = false
function sayit(letters)
for _,v in ipairs(letters) do
v == "a" then print("aah")
elseif v == "b" then print("bee")
elseif v == "c" then print("see")
elseif v == "d" then print("dee")
elseif v == "e" then print("eee")
elseif v == "f" then print("eff")
elseif v == "g" then print("gee")
elseif v == "h" then print("aych")
elseif v == "i" then print("eye")
elseif v == "j" then print("jay")
elseif v == "k" then print("kay")
elseif v == "l" then print("el")
elseif v == "m" then print("em")
elseif v == "n" then print("en")
elseif v == "o" then print("ooh")
elseif v == "p" then print("pee")
elseif v == "q" then print("queue")
elseif v == "r" then print("arr")
elseif v == "s" then print("ess")
elseif v == "t" then print("tee")
elseif v == "u" then print("you")
elseif v == "v" then print("vee")
elseif v == "w" then print("doubleyou")
elseif v == "x" then print("ex")
elseif v == "y" then print("why")
elseif v == "z" then print(is_canadian and "zed" or "zee")
elseif v == "?" then print(is_canadian and "eh" or "")
print("blah")
sayit{'h','e','l','l','o','?'}
When there are many tests as such, the comparison chain is not always the most efficient.
If the number of elements in letters is M and the number of tests is N, then the complexity is O(M*N), or potentially quadratic.
A more minor concern is the syntax redundancy of having "v ==" for each test.
These concerns (minor as they may be) have been noted elsewhere as well
If we rewrite this as a lookup table, the code can run in linear-time, O(M), and without the redundancy so that the logic is easier to modify at whim:
local t = {
a = "aah",
b = "bee",
c = "see",
d = "dee",
e = "eee",
f = "eff",
g = "gee",
h = "aych",
i = "eye",
j = "jay",
k = "kay",
o = "ooh",
p = "pee",
q = "queue",
r = "arr",
s = "ess",
t = "tee",
u = "you",
v = "vee",
w = "doubleyou",
y = "why",
z = function() return is_canadian and "zed" or "zee" end,
['?'] = function() return is_canadian and "eh" or "" end
function sayit(letters)
for _,v in ipairs(letters) do
local s = type(t[v]) == "function" and t[v]() or t[v] or "blah"
sayit{'h','e','l','l','o','?'}
C compilers can optimize the switch statement in a roughly similar way via what is called a jump table, at least under suitable conditions.
Note how the table construction was placed outside the block to avoid recreating the table for each use (table constructions cause heap allocations).
This improves performance but has the side-effect of moving the lookup table further from its usage.
We might address that with this minor change:
function sayit(letters)
t = t or {a = "ahh", .....}
for _,v in ipairs(letters) do
local s = type(t[v]) == "function" and t[v]() or t[v] or "blah"
sayit{'h','e','l','l','o','?'}
The above is a practical solution that is the basis for the more elaborate approaches given below.
Some are the below solutions are more for syntactic sugar or proof-of-concept rather than recommended practices.
Simple Table of functions
A simple version of a switch statement can be implemented using a table to map the case value to an action. This is very efficient in Lua since tables are hashed by key value which avoids repetitive if &case& then ... elseif ... end statements.
action = {
[1] = function (x) print(1) end,
[2] = function (x) z = 5 end,
["nop"] = function (x) print(math.random()) end,
["my name"] = function (x) print("fred") end,
Usage (Note, that in the following example you can also pass parameters to the function called) :-
action[case](params)
This is pseudocode for the above:
switch (caseVariable)
case 1: print(1)
case 2: z=5
case "nop": print(math.random())
case "my name": print("fred")
Case method
This version uses the function switch(table) to add a method case(table,caseVariable) to a table passed to it.
function switch(t)
t.case = function (self,x)
local f=self[x] or self.default
if type(f)=="function" then
error("case "..tostring(x).." not a function")
a = switch {
[1] = function (x) print(x,10) end,
[2] = function (x) print(x,20) end,
default = function (x) print(x,0) end,
Caseof method table
Here's yet another implementation of a "switch" statement. This one is based on Luiz Henrique de Figueiredo's switch statement presented in a list message dated Dec 8 1998, but the object/method relationship has been flipped around to achieve a more traditional syntax in actual use.
Nil case variables are also handled - there's an optional clause specifically for them (something I wanted), or they can fallback to the default clause.
(easily changed)
Return values from the case statement functions are also supported.
function switch(c)
local swtbl = {
casevar = c,
caseof = function (self, code)
if (self.casevar) then
f = code[self.casevar] or code.default
f = code.missing or code.default
if type(f)=="function" then
return f(self.casevar,self)
error("case "..tostring(self.casevar).." not a function")
return swtbl
Here's sample usage:
switch(c) : caseof {
= function (x) print(x,"one") end,
= function (x) print(x,"two") end,
default = function (x) print(x,"default") end,
missing = function (x) print(x,"missing") end,
print("expect to see 468:
switch(2):caseof{
[1] = function(x) return 234 end,
[2] = function(x) return 345 end
Switch returns function instead of table
Yet another implementation of an even more "C-like" switch statement. Based on Dave code above. Return values from the case statement functions are also supported.
function switch(case)
return function(codetable)
f = codetable[case] or codetable.default
if type(f)=="function" then
return f(case)
error("case "..tostring(case).." not a function")
Example usage:
for case = 1,4 do
switch(case) {
[1] = function() print("one") end,
[2] = print,
default = function(x) print("default",x) end,
Note that this works, but trashes the gc with a function closure each time the switch is used (as do most of the examples on this page). Still, i like the way it works. Just don't -) --
Switch returns callable table instead of function
This one has the exact same syntax as the one above, but is written much more succinctly, as well as differentiates between the default case and a string containing the word 'default'.
Default, Nil = {}, function () end
function switch (i)
return setmetatable({ i }, {
__call = function (t, cases)
local item = #t == 0 and Nil or t[1]
return (cases[item] or cases[Default] or Nil)(item)
Nil here is an empty function because it will generate a unique value, and satisfy the
requirement in the return statement call, while still being having a value of true to allow its use in the and or ternary. In Lua 5.2, however, a function might not create a new value if one is present, which will raise problems if you somehow end up using switch to compare functions. Should it ever come to this, a solution would be to define Nil with yet another table: setmetatable({}, { __call = function () end }).
A case-insensitive variant can be made by adding if type(item) == "string" then item = string.lower(item) end, provided all the keys of the table are done the same way. Ranges could potentially be represented by an __index function metatable on the cases table, but that would break the illusion: switch (case) (setmetatable({}, { __index = rangefunc })).
Example usage:
switch(case) {
[1] = function () print"number 1!" end,
[2] = math.sin,
[false] = function (a) return function (b) return (a or b) and not (a and b) end end,
Default = function (x) print"Look, Mom, I can differentiate types!" end,
[Default] = print,
[Nil] = function () print"I must've left it in my other jeans." end,
I can't say anything for its resource usage, however, especially compared to other examples here.
Using vararg function to build case list
In the interest of more 'stupid Lua tricks', here's yet another implementation:
(Edit: It is necessary that the default functionality is put last in the ... parameter)
function switch(n, ...)
for _,v in ipairs {...} do
if v[1] == n or v[1] == nil then
return v[2]()
function case(n,f)
return {n,f}
function default(f)
return {nil,f}
Example usage:
switch( action,
case( 1, function() print("one")
case( 2, function() print("two")
case( 3, function() print("three")
default( function() print("default") end)
Case expression types other than just matching a value
Here's one from TheGreyKnight, which can handle cases representing ranges, lists and default actions. It also supports mismatch cases and fall-through (ie, continue with the next statement). The part that checks for the "-fall" suffix could probably be made more efficient, but I think this version is easier to read. The functions which are used as the bodies of the cases are passed a single parameter, which is the final form of the switch expression (a feature I've longed for in switches for ages)
The supporting functions contain(x, valueList) and range(x, numberPair) merely test whether or not x is a value in the table valueList or a number in the closed range specified by the two elements of numberPair.
function switch(term, cases)
assert(type(cases) == "table")
local casetype, caseparm, casebody
for i,case in ipairs(cases) do
assert(type(case) == "table" and count(case) == 3)
casetype,caseparm,casebody = case[1],case[2],case[3]
assert(type(casetype) == "string" and type(casebody) == "function")
(casetype == "default")
((casetype == "eq" or casetype=="") and caseparm == term)
((casetype == "!eq" or casetype=="!") and not caseparm == term)
(casetype == "in" and contain(term, caseparm))
(casetype == "!in" and not contain(term, caseparm))
(casetype == "range" and range(term, caseparm))
(casetype == "!range" and not range(term, caseparm))
return casebody(term)
(casetype == "default-fall")
((casetype == "eq-fall" or casetype == "fall") and caseparm == term)
((casetype == "!eq-fall" or casetype == "!-fall") and not caseparm == term)
(casetype == "in-fall" and contain(term, caseparm))
(casetype == "!in-fall" and not contain(term, caseparm))
(casetype == "range-fall" and range(term, caseparm))
(casetype == "!range-fall" and not range(term, caseparm))
casebody(term)
Example Usage:
switch( string.lower(slotname), {
{"", "sk", function(_)
PLAYER.sk = PLAYER.sk+1
{"in", {"str","int","agl","cha","lck","con","mhp","mpp"}, function(_)
PLAYER.st[_] = PLAYER.st[_]+1
{"default", "", function(_)end}
Another form
function switch (self, value, tbl, default)
local f = tbl[value] or default
assert(f~=nil)
if type(f) ~= "function" then f = tbl[f] end
assert(f~=nil and type(f) == "function")
return f(self,value)
It avoids repeating functions, since if tbl's entry is a string/number, it follows this value as the case to seek for.
I would call this multiple case statements.
Example usage:
local tbl = {hello = function(name,value) print(value .. " " .. name .. "!") end,
bonjour = "hello", ["Guten Tag"] = "hello"}
switch("Steven","hello",tbl,nil)
switch("Jean","bonjour",tbl,nil)
switch("Mark","gracias",tbl,function(name,val) print("sorry " .. name .. "!") end)
A Case Statement implemented with Token Filter Macros
My feeling is that switch is the wrong model, but that we should look at Pascal's case statement as more appropriate inspiration. Here are some possible forms:
is 10,11: return 1
is 12: return 2
is 13 .. 16: return 3
else return 4
matches '^hell': return 5
matches '(%d+)%s+(%d+)',result:
return tonumber(result[1])+tonumber(result[2])
else return 0
You can provide a number of values after is, and even provide a range of values. matches is string-specific, and can take an extra parameter which is filled with the resulting captures.
This case statement is a little bit of syntactical sugar over a chain of elseif statements, so its efficiency is the same.
This is implementable using token filter macros ( the source contains an example implementation), so people can get a feeling for its use in practice. Unfortunately, Lua complains of a malformed number if there is no whitespace around ... Also result has to be global.
Metalua's pattern matching
comes with an extension that performs structural pattern matching, of which switch/case is just a special case. The example above would read:
-{ extension 'match' }
match k with
-& return 1
-& return 2
| i if 13&=i and i&=16 -& return i-10
-& return 4
No special handling currently exists for regular expressions string matching, although it can be worked around by guards. Proper support can be added quite easily, and will likely be included in a future release.
Relevant resources:
* Step-by-step tutorial about implementing a pattern matching extension, and the corresponding sources.
* The latest optimized implementation
Object Oriented Approach
You can find full code in .
local fn = function(a, b) print(tostring(a) .. ' in ' .. tostring(b)) end
local casefn = function(a)
if type(a) == 'number' then
return (a & 10)
local s = switch()
s:case(0, fn)
s:case({1,2,3,4}, fn)
s:case(casefn, fn)
s:case({'banana', 'kiwi', 'coconut'}, fn)
s:default(fn)
s:test('kiwi')
I don't get it.
I'm a hard core C/C++ programmer but not once have I longed for switch in Lua.
Why not take this to its extreme and just have Lua parse a real C switch statement?
Anyone who can achieve that will learn why it wasn't necessary in the first place.
--Troublemaker
How about to avoid: a) a linear search through options, b) to avoid creating garbage every time the case is used, and c) because the if-elseif-else solution is ugly. The condition is repeated N times which obscures and complicates the code. A simple switch on numbers could jump quickly to the code to be executed and doesn't have to generate a closure or a table every time as in the code below.
Actually, I've never used this code as a switch statement. I thought it made good example code for Lua's features and I may use it one day, but I never have! :-) I think its because you have the associative arrays/tables to map values, so you can design around having to need a switch statement. The times when I do think about needing a switch is when I'm switching on value type. --Alsopuzzled
I've never really needed a switch in Lua either, but these examples made me bend my brain trying to see why they work. Lua's flexibility continues to amaze me. I'm now that much closer to the . --Initiate
The issues with these implementations are that they either can't access local variables or they create not just one closure but one closure per switch-branch plus a table. As such, they aren't particular good as substitutes for a switch statement. That being said, I haven't been suffering too much pain related to the lack of a switch statement in Lua. --
The lookup table example is a perfectly practical and readable solution that doesn't suffer from those problems at all. It's even mentioned in the page that examples beyond that point are mostly non-practical thought experiments -- Colin Hunt
I am using LUA for scripting my self created web server module. It's terribly fast (and much much faster than my previous PHP version). In here, a switch statement would really be great to case through all GET["subfunction"] possibilities. The only reason is that the only thinkable alternative (if-elseif) is ugly. The other alternatives are as previously indicated very beautiful, world-opening, but a terrible waste of resources. --Scippie
Edit: Maybe I was wrong about the "terrible waste of resources". This is what scripting is all about and the language is made to be handled this way. --Scippie
You don't need a switch statement, if you can just map with a table or use elseifs. The real problem starts when you want to use fallthrough. I am currently working with a database and I need to be able to update it. Since it needs to be updated one step at a time, you jump to the place that updates to the next version and then fall-through until you arrive at the newest version. For that, though, you need either computed goto or a switch statement. Which Lua both lacks. --Xandaros
"@Xandrous There is a goto now"
The above code was pulled from lua-l or donated by Lua users. Thanks to LHF, DaveBollinger, , .
& Last edited June 23,

我要回帖

更多关于 too many connections 的文章

 

随机推荐