Lua
Essentials
- Use
% luato run interactively, or% lua -i file.lua % lua [options] [script [args]]- A global var
arg:scriptisarg[0] - Preceding options to go negative indices e.g.,
arg[-1]
- A global var
- Use
dofileorloadfileto load a file - Use
--for one line comment - Use
--[[ code ]]for multiple lines of comments - Optional
semicolon - Variables are typeless, and global by default (unless
local)type(var): nil, boolean, number, string, userdata, function, table
nilis undefined var, and be used to reset a var- In conditional statements,
nilandfalseisfalse, everything else istrue- Event
0and emptry strings aretrue
- Event
andandorare short-circuit eval: they eval 2nd arg only when necessaryandhas higher precedence thanor4 and 5–>5nil or false–>falsex = x or v–>if not x then x = v endx == y and a or b–> ifx == ythenaelsebnot 0–>falsebecause0istrue
- Inequality operator is
~=
Variables
- Variables are global by default; use
localfor local ones - In interactive mode, each line is a local scope
- Use
do - endto fine control the scope - Modeule
strict.luato check global var local foo = foodeclare a localfoowith the value of global varfoo
Control
-- if else then
if a < 0 then a = 0 end
if a < b then return a else return b end
if line > MAX then
line = 0
elseif line < MIN then
line = MIN
else
line = 1
end
-- use break to break a loop
while a[i] do
print(a[i])
end
repeat
line = io.read()
until line ~=""
-- numerical `for`
-- from exp1 to exp2, with step exp3
-- optional exp3, default 1
-- all three exp would be evaluated only once
--- all three exp were localto the loop
for var = exp1, exp2, exp3 do
something()
end
-- generic for
-- traverse all values in an iterator
-- goto, use ::name:: for label
-- cannot goto into a block (or a function)
-- cannot jump out of a function
-- cannot jump into the scope of a local var
::s1:: do
local c = io.read(1)
if c == '0' then goto s2
elseif c == nil then print'ok'; return
else goto s1
end
end
Numbers
- Integer was introducted in 5.3
- Both integer and float have type “number”
- Integers and floats with the same value compare as equal
math.typecan distinguish between floats and int- Since Lua 5.3
math.type(3)–>integermath.type(3.0)–>float
- Use
0xfor hexadecimal constants:0xff–>2550x0.2–>0.1250x1p-1–>0.5
4
0.4
4.57e-3
0.3e12
5E+20
1 == 1.0 -- true
13.0 + 25 -- 28.0
-- Since 5.3, `//` floor division
-- rounds the quotient towards minus infinity
-- both op are int, result in int; otherwise, result in float
3 // 2 -- 1
3.0 // 2 -- 1.0
-9 // 2 -- -5
a % b == a - ((a // b) * b)
mathmodule
math.pi()
math.abs()
math.type()
math.sin() -- cos, tan, asin etc.
math.max() -- min
math.random() -- [0, 1)
math.random(n) -- int, [1, n]
math.random(x, y) -- int, [x, y]
math.randomseed()
math.floor() -- ceil, modf
math.modf(3.3) --> 3, 0.3
math.huge() -- inf
math.maxinteger
math.mininteger
math.tointeger()
Strings
- Strings are immutable values
- Use
#to get the length of a string - First string char has index 1
- Use
..to concatenate two strings - Double and single quotes are equivalent other than escapes
- Use
\u{hhh}with hexadecimal digits for UTF-8 char\u{3b1}is α
- Use
[[ ... ]]fo long strings
page = [[
<html>
<body>
Body
</body>
</html>
]]
tonumber()convert a string to a number; returnsnilif invalidtonumber("100101", 2)–> specify base2
Stringlibrary
string.len(s) -- same as `#s`, and s:len()
string.rep(s, n) -- repeat s n times
string.reverse()
string.lower() -- upper
string.lower(a) < string.lower(b)
string.sub(s, i, j) -- negative counts from end
s = "[in brackets]"
string.sub(s, 2, -2) -- return chars between []
string.char(97) -- a
string.byte("a") -- 97
string.char(97, 98, 99) -- abc
string.byte("abc", -1) -- 99
string.byte(s, 1, -1) -- list with codes of all chars in s
string.format() -- same as C printf
-- %d for decimal int, %02d zero padding with at least two digits; %2d use blank for padding
-- %x for hexadecimal
-- %f for floating-point numbers, %.4f
-- %s for string
-- return first and last positions
-- return nil if none found
string.find(s, char)
string.gsub(s, old_char, new_char)
-- use utf8 library
utf8.len("résumé") -- 6
utf8.char(114, 233, 115, 117, 109, 233) -- résumé
utf8.codepoint("résumé", 6, 7) -- 109 233
Tables
- Tables are the only data structure
- They are objects, associative array (key=value)
a = {}– create a table- Any type can be index
- Table is always anonymous - a var is not fixed to the table itself
#gives the length of the sequence represented by the table; if there isnilin between, it only works for sequence
a = {}
a["x"] = 10 -- string as index
a.x -- same as a["x"], but not a[x], only works with string index
a.y -- nil
a[1] = 20 -- number as index
a[2.0] -- automatically to a[2]
a[2.1] -- still a[2.1]
-- when no index is provided, it's automatically starting from 1
a = {x = 10, y = 20, 30, 40}
-- same as a = {["x"] = 10, ["y"] = 20, [1] = 30, [2] = 40}
a[1] -- 30
a[2] -- 40
p = {
color="blue", -- p.color
thickness=2, -- p.thicknes
{x=0, y=0}, -- p[1].x = 0
{x=0, y=1} -- p[2]
}
- Use
pairsto traverse all key-value pairs - The order is undefined
- Use
ipairsto ensure order - use
#too
for k, v in pairs(t) do
print(k, v)
end
for k = 1, #t do
print(k, t[k])
end
-
Safe navigation:
(a or {}).b -
Table library
table.insert(t, k, v)
table.insert(t, v) -- insert at the end
table.remove(t) -- return the last value
-- move from index f until e (inclusive) to position t
table.move(a, f, e, t)
table.move(a, 1, #a, 2) -- shift all elements right
a[1] = newElement
table.move(a, 2, #a, 1) -- shift left
a[#a] = nil -- need to explicitly erase the last element
-- extra optional para: a table
table.move(a, 1, #a, 1, {}) -- returns a clone
table.move(a, 1, #a, #b + 1, b) -- appends list a to end of b
-- table.unpack takes a list and returns all elements
-- reverse of table.pack
print(table.unpack{10,20,30}) --> 10 20 30
a,b = table.unpack{10,20,30} -- a=10, b=20, 30 is discarded
print(table.unpack({"Sun", "Mon", "Tue", "Wed"}, 2, 3)) --> Mon Tue
Functions
foo(args)–()is optional if there is only one argument that is either a string or{}
print "hello world" -- print("hello world")
f{x = 10, y = 20} -- f({x=10, y=20})
o:foo(x)for object-oriented calls
function add (a)
something()
end
-- same as
add = function (a)
something()
end
- Functions are variadic - can take a variable number of args
- Use
...to indicate variadic and for “vararg” expression
function f (a, b) print(a, b) end
f() --> nil, nil
f(3) --> 3, nil
f(3, 4, 5) --> 3, 4
-- variadic
function foo (...)
local a, b = ...
print(a, b)
end
-- can have fixed parameter before the dots
function foo (fmt, ...)
return io.write(string.format(fmt, ...))
end
- Multiple results
function foo0 () end -- returns no results
function foo1 () return "a" end -- returns 1 result
function foo2 () return "a", "b" end -- returns 2 results
function foo0 () end -- returns no results
function foo1 () return "a" end -- returns 1 result
function foo2 () return "a", "b" end -- returns 2 results
x,y = foo0() -- x=nil, y=nil
x,y = foo1() -- x="a", y=nil
x,y,z = foo2() -- x="a", y="b", z=nil
x,y = foo2(), 20 -- x="a", y=20 ('b' discarded)
x,y = foo0(), 20, 30 -- x=nil, y=20 (30 is discarded)
print(foo0()) --> (no results)
print(foo1()) --> a
print(foo2()) --> a b
print(foo2(), 1) --> a 1
print(foo2() .. "x") --> ax (see next)
t = {foo0()} -- t = {} (an empty table)
t = {foo1()} -- t = {"a"}
t = {foo2()} -- t = {"a", "b"}
t = {foo0(), foo2(), 4} -- t[1] = nil, t[2] = "a", t[3] = 4
-- use `()` to force only one result returned
print(foo(1)) --> a
print(foo(2)) --> a b
print(foo(0)) -- (no results)
print(foo(3)) -- (no results)
print((foo0())) --> nil
print((foo1())) --> a
print((foo2())) --> a