Dies ist eine alte Version des Dokuments!
Programming in Lua (5.0) Tutorial — Reference Manual — Short Reference — IBM intro: Embeddable scripting with Lua — Linux Journal intro: A Look at Lua
#!/usr/bin/lua
Use global table arg
local inp= io.stdin:read() -- Read a line from stdion print() -- Print a line to stdout io.stdout:write() -- Print a string to stdout io.stderr:write() -- Print a string to stderr
This C code
d= a ? b : c
is in lua:
d= a and b or c
Note that this works only for single assignment. Use auxiliary tables for mulitiple assignment:
d1, d2 = table.unpack(a and {b1, b2} or {c1, c2})
for i = 0,24,4 do -- start, end (including), step print(i) end
Use #
operator
-- Iterate over array part: for i,v in ipairs(now) do print(i,v) end -- Iterate over complete table: for k,v in pairs(now) do print(k,v) end
pairs()
#!/usr/bin/lua -- Numbers: a=3 -- a contains 3 b=a -- b contains 3 a=4 -- a contains 4, b still contains 3 print(a,b) -- 4 3 -- Booleans: a=true; b=a; a=false print(a,b) -- false true -- Strings: a="World" -- a points to the string "World" b=a -- b points to the same string a="Hello" -- a points to "World", b still points to "Hello" print(a,b) --> Hello World -- Functions: a= function() print("World") end b=a -- a and b point to the same function: print(a,b) --> function: 0x80500e8 function: 0x80500e8 a= function() print("Hello") end -- a points to a new function and b still points to the old function: print(a,b) --> function: 0x8050a48 function: 0x80500e8 a() -- Hello b() -- World
#!/usr/bin/lua -- Tables: a={3} b=a; -- a and b point to the same table: print(a,b) -- table: 0x80509e0 table: 0x80509e0 print(a[1],b[1]) -- 3 3 a[1]=4; print(a[1],b[1]) -- 4 4 b[1]=5 print(a[1],b[1]) -- 5 5 a={6} -- a points to a new table and b still points to the old table: print(a,b) -- table: 0x8050a30 table: 0x80509e0 print(a[1],b[1]) -- 6 5 b[1]=7 print(a[1],b[1]) -- 6 7
pcall()
converts an error raising function into an error returning function.
assert()
or similar converts an error returning function into an error raising function.
A function which returns the error forces the user of that function to always check the return code (or convert to raise) , regadless if he wants to handle the error or just pass it upward.
A function which raises the error can not get forgotten to check for errors.
If the user wants to pass the error upward, checking and converting can be avaoided completely if both the called function and the caller use error raising. In any other case he has to check and/or convert:
callerv callee→ | return | raise |
---|---|---|
return | check | pcall() + check |
raise | assert() | nothing |
If the user wants to handle the error, he simply checks the return value of an error returning function. If the function raises the error, the user must convert it to a error returning function by help of pcall().
-- rectangle prototype: rectangle_proto= {species="rectangle"} function rectangle_proto:area() return self.width * self.height end -- rectangle constructor: function new_rectangle(width, height) local rectangle= {width= width, height= height} setmetatable(rectangle, {__index=rectangle_proto}) return rectangle end -- rectangle usage: rectangle= new_rectangle(3,4) print(rectangle:area()) --> 12 print(rectangle.species) --> rectangle -- circle prototype: circle_proto= {species="circle"} function circle_proto:area() return self.radius^2 * math.pi end -- circle constructor: function new_circle(radius) local circle= {radius= radius} setmetatable(circle, {__index=circle_proto}) return circle end circle= new_circle(1) print(circle:area()) --> 3.14 print(circle.species) --> circle
Classic single inheritance chain:
-- Inheritance: shape prototype: shape_proto= {family="shape"} function shape_proto:get_species() return self.species end function shape_proto:get_family() return self.family end setmetatable(rectangle_proto, {__index=shape_proto}) setmetatable(circle_proto, {__index=shape_proto}) print(circle:get_family().."/"..circle:get_species()) --> shape/circle print(rectangle:get_family().."/"..rectangle:get_species()) --> shape/rectangle
Lua print()
does not look for a tostring()
method directly in the table, instead it looks for a method called __tostring()
in its metatable. Thus, to enable both print(myobject:tostring())
(explicit call) and print(myobject)
(implicit call), provide the tostring() method in the prototype table of the object and set __tostring
attribute of the metatable to that method:
-- rectangle prototype: rectangle_proto= {} function rectangle_proto:tostring() return "["..self.width.."|"..self.height.."]" end -- rectangle constructor: function new_rectangle(width, height) rectangle= {width= width, height= height} setmetatable(rectangle, { __index=rectangle_proto, __tostring=rectangle_proto.tostring }) return rectangle end -- rectangle usage: rectangle= new_rectangle(3,4) print(rectangle:tostring()) --> [3|4] print(rectangle) --> [3|4]
This works also if tostring()
is defined in the base clase:
-- shape as base class: shape_proto= {} function shape_proto:tostring() return "["..self.width.."|"..self.height.."]" end -- rectangle prototype inherits from shape: rectangle_proto= {} setmetatable(rectangle_proto, { __index=shape_proto }) -- rectangle constructor: function new_rectangle(width, height) rectangle= {width= width, height= height} setmetatable(rectangle, { __index=rectangle_proto, __tostring=rectangle_proto.tostring }) return rectangle end -- rectangle usage: rectangle= new_rectangle(3,4) print(rectangle:tostring()) --> [3|4] print(rectangle) --> [3|4]
local M= {} local private= {} -- holds private data of all objecs in subtables -- Class Point: -- local Point_proto= {} -- Class prototype function Point_proto:set(x,y) local priv= private[self] priv.x= x priv.y= y end function Point_proto:get() local priv= private[self] return priv.x, priv.y end function Point_proto:tostring() local priv= private[self] return "["..priv.x.."|"..priv.y.."]" end Point_proto.__index = Point_proto Point_proto.__newindex= function() assert(false,"object is write-protected") end setmetatable(Point_proto, { -- ensure read protection for Point and all childs __index= function() assert(false, "object is read-protected") end }) function M.new_Point(x,y) -- constructor local instance= {} setmetatable(instance, Point_proto) private[instance]= {} -- create private part of object instance:set(x,y) return instance end return M
#!/usr/bin/lua local point= require "point" local print_r= function(table) for key,value in pairs(table) do io.write("[", key, "] = ", tostring(value), "\n") end end local p= point.new_Point(3,4) --p.x= 8 --> Write access throws an error --print(p.y) --> Read access throws an error print(p:tostring()) --> [3|4] print_r(p) --> prints nothing
local M= {} local private= {} -- holds private data of all objecs in subtables -- Class Point: -- -- ... -- CLASS MovablePoint: -- local MovablePoint_proto= {} -- Class prototype function MovablePoint_proto:move(dx, dy) local priv= private[self] priv.x= priv.x+dx priv.y= priv.y+dy end MovablePoint_proto.__index = MovablePoint_proto MovablePoint_proto.__newindex= Point_proto.__newindex setmetatable(MovablePoint_proto, Point_proto) -- Inherit from Point function M.new_MovablePoint(x,y) -- constructor local instance= M.new_Point(x,y) -- call parent constructor setmetatable(instance, MovablePoint_proto) return instance end return M
#!/usr/bin/lua local point= require "point" -- ... local mp= point.new_MovablePoint(5,6) mp.x= 9 --> Write access throws an error print(mp.y) --> Read access throws an error print(mp:tostring()) --> [5|6] mp:move(2,1) print(mp:tostring()) --> [7|7] print_r(mp) --> prints nothing
To run some code sitting in a different file, use dofile()
To load global variables of an external (config) file into a table locally, you have to pass the table as environment:
a="Harry" b="Hirsch"
#!/usr/bin/lua local extenv={} local chunk= loadfile("config.lua", "t" , extenv) chunk() for k,v in pairs(extenv) do io.write("[", k, "] = ", tostring(v), "\n") end
[a] = Harry [b] = Hirsch
See ModuleDefinition and LuaStyleGuide → Modules
module()
is deprecated!
now= os.time()
-- Return a table containing hour, min, wday, day, ... of current time: now = os.date("*t") -- Return a table containing hour, min, wday, day, ... of a certain time: atime = os.date("*t", timestamp) -- Return a formated string of current time: now = os.date("Today is %A") -- Today is Thursday
do var= 0 for i=1,102000000 do var= var+1 end end -- real 0m4.516s
do local var= 0 for i=1,102000000 do var= var+1 end end -- real 0m1.003s
local var= 0 do for i=1,102000000 do var= var+1 end end --real 0m0.970s
do local var= 0 local closure= function() for i=1,102000000 do var= var+1 end end closure() end -- real 0m1.666s
do local tab= {var= 0} for i=1,102000000 do tab.var= tab.var+1 end end -- real 0m4.248s
do local tab= {0} for i=1,102000000 do tab[1]= tab[1]+1 end end -- real 0m4.767s
Tested with Lua 5.2
table.concat()
See also:
A newly created coroutine is in state supended
:
co1= coroutine.create(function() end) print(coroutine.status (co1)) --> suspended
A coroutine which resumes another coroutine goes from state running
to normal
while the resumed couroutine goes from state suspended
torunning
:
co1= coroutine.create(function() print("in co1: state main:", coroutine.status(main)) print("in co1: state co1", coroutine.status(co1)) end) main= coroutine.running() -- get handle to main coroutine print("in main: state main:", coroutine.status(main)) print("in main: state co1:", coroutine.status(co1)) coroutine.resume(co1)
Result: in main: state main: running in main: state co1: suspended in co1: state main: normal in co1: state co1 running
A running
couroutine can yield() back to its resumer, which puts the resumer back to running
and itself back to suspended
:
co1= coroutine.create(function() print("in co1: state main:", coroutine.status(main)) print("in co1: state co1", coroutine.status(co1)) coroutine.yield() end) main= coroutine.running() -- get handle to main coroutine coroutine.resume(co1) print("in main: state main:", coroutine.status(main)) print("in main: state co1:", coroutine.status(co1))
Result: in co1: state main: normal in co1: state co1 running in main: state main: running in main: state co1: suspended
Alternatively a running
couroutine can resume another coroutine (which is in state suspended
):
co1= coroutine.create(function() coroutine.resume(co2) end) co2= coroutine.create(function() print("in co2: state main:", coroutine.status(main)) print("in co2: state co1", coroutine.status(co1)) print("in co2: state co2", coroutine.status(co2)) end) main= coroutine.running() -- get handle to main coroutine coroutine.resume(co1)
Result: in co2: state main: normal in co2: state co1 normal in co2: state co2 running
But a running
couroutine cannot resume a non-suspended coroutine. Only coroutines in state suspended
can be resumed:
co1= coroutine.create(function() local res, err= coroutine.resume(main) print(res, err) end) main= coroutine.running() -- get handle to main coroutine coroutine.resume(co1)
Result: false cannot resume non-suspended coroutine
#!/usr/bin/lua co= coroutine.create(function() while true do io.stderr:write('co: waking up\n') local inp= io.stdin:read() io.stderr:write('co: read "'..inp..'", going to sleep\n') coroutine.yield(inp) end end) while true do io.stderr:write('main: going to sleep\n') local state, oup= coroutine.resume(co) io.stderr:write('main: waking up\n') print('> '..oup) end