NOTE

1.1 Lua

Lua is a lightweight scripting language suitable for embedding into applications. These notes cover Lua data types, variables, operators, control flow, error handling, modules, and basic object-oriented patterns.

LuaCreated Updated 3 min readhistorical

This is a historical learning note and may contain outdated or incomplete understanding.

1. LUA

A scripting language used to be embedded into applications in a flexible way.

2. Data Types

print(type(nil))
print(type(1))
print(type(1.1))
print(type("test"))
print(type(true))
print(type(type))
print(type({}))
data = {
    name="zsk"
}
print(type(data))

-- Output
nil
number
number
string
boolean
function
table
table

2.1. nil

  • Represents an invalid value (equivalent to false in conditional expressions).

  • For global variables and tables, nil also has a “delete” effect. Assigning nil to a global variable or a variable in a table is equivalent to deleting it.

    
    tab1 = { key1 = "val1", key2 = "val2", "val3" }
    for k, v in pairs(tab1) do
        print(k .. " - " .. v)
    end
     
    tab1.key1 = nil
    for k, v in pairs(tab1) do
        print(k .. " - " .. v)
    end

2.2. boolean

  • Contains two values: false and true.

  • Lua treats false and nil as false; everything else is true, and the number 0 is also true.

    if true and 0 then
        print("true")
    end
    
    if false or nil then
        print("at least one is true")
    else
        print("false and nil are both false")
    end
    -- Output
    true
    false and nil are both false

2.3. number

  • Represents double-precision real floating-point numbers.

    print(type(2))
    print(type(2.2))
    print(type(0.2))
    print(type(2e+1))
    print(type(0.2e-1))
    print(type(7.8263692594256e-06))
    -- Output
    number
    number
    number
    number
    number
    number

2.4. string

  • A string is represented by a pair of double quotes or single quotes.

  • Two square brackets [[ ]] can also be used to represent a “block” of string content.

    html = [[
    <html>
    <head></head>
    <body>
        <a href="http://www.runoob.com/">RUNOOB Tutorial</a>
    </body>
    </html>
    ]]
    print(html)
    
    -- Output
    <html>
    <head></head>
    <body>
        <a href="http://www.runoob.com/">RUNOOB Tutorial</a>
    </body>
    </html>
  • String concatenation uses ...

    print("a" .. "b")
    print(123 .. 456)
    -- Output
    ab
    123456
  • String length uses #.

    print(#"sssss")
    -- Output
    5
  • Using + on numeric strings attempts to convert them to numbers.

    print("11" + "22")
    -- Output
    33
  • String operation APIs

    -- Convert the whole string to uppercase
    print(string.upper("test"))--TEST
    -- Convert the whole string to lowercase
    print(string.lower("TEST"))--test
    -- Replace content in a string
    print(string.gsub("aaaa", "a", "z", 3))--zzza	3
    -- Search for specified content in a target string (the third parameter is the index), and return its exact position. Return nil if it does not exist.
    print(string.find("Hello Lua user", "Lua", 1))--7	9
    -- Reverse a string
    print(string.reverse("Lua"))--auL
    -- Return a printf-like formatted string
    print(string.format("the value is:%d", 4))--the value is:4
    -- char converts integers to characters and concatenates them; byte converts a character to an integer value (a character can be specified, default is the first character)
    print(string.char(97, 98, 99, 100))--abcd
    print(string.byte("ABCD", 4))--68
    -- Calculate string length
    print(string.len("abc"))--3
    -- Return n copies of the string
    print(string.rep("abcd", 2))--abcdabcd
    -- Concatenate two strings
    print("ss" .. "nn")--ssnn
    -- Extract a substring
    print(string.sub("sourcestr", 1, 3))--sou
    %c - Accept a number and convert it to the corresponding character in the ASCII table
    %d, %i - Accept a number and convert it to signed-integer format
    %o - Accept a number and convert it to octal format
    %u - Accept a number and convert it to unsigned-integer format
    %x - Accept a number and convert it to hexadecimal format using lowercase letters
    %X - Accept a number and convert it to hexadecimal format using uppercase letters
    %e - Accept a number and convert it to scientific-notation format using lowercase e
    %E - Accept a number and convert it to scientific-notation format using uppercase E
    %f - Accept a number and convert it to floating-point format
    %g(%G) - Accept a number and convert it to the shorter form between %e (%E for %G) and %f
    %q - Accept a string and convert it to a format that can be safely read by the Lua compiler
    %s - Accept a string and format it according to the given parameters

2.5. function

  • Functions written in C or Lua.

    function fun(a, b, c)
        return a, b, c
    end
    
    value1, value2, value3 = fun(1, 2, 3, 4, 5)
    print(value1, value2, value3)
    -- Output
    1	2	3
  • Functions are first-class citizens and can be assigned to variables.

    function testFun(tab, fun)
        for k, v in pairs(tab) do
            print(fun(k, v));
        end
    end
    
    tab = { key1 = "val1", key2 = "val2" };
    testFun(tab,
            function(key, val)
                -- Anonymous function
                return key .. "=" .. val;
            end
    );
    -- Output
    key1=val1
    key2=val2
  • Functions are global by default unless local is added.

    local function test()
    
    end
    
    test()
  • Multiple return values are supported.

    local function test()
        return 1, 2
    end
    
    print(test())
  • Variable-length arguments are supported. Fixed arguments must come before variable-length arguments.

    function average(...)
        result = 0
        local arg = { ... }    --> arg is a table, a local variable
        for i, v in ipairs(arg) do
            result = result + v
        end
        print("a total of " .. #arg .. " numbers were passed in")
        return result / #arg
    end
    
    print("average is", average(10, 5, 3, 4, 5, 6))
    -- Output
    a total of 6 numbers were passed in
    average is	5.5

2.6. table

  • A table is actually an associative array (similar to a map).

    tbl1 = { 1, 2, 3 }
    for k, v in pairs(tbl1) do
        print(k .. " : " .. v)
    end
    
    print("======================")
    
    tbl2 = { a = "aa", b = "bb" }
    for k, v in pairs(tbl2) do
        print(k .. " : " .. v)
    end
    print("======================")
    
    
    -- Output
    1 : 1
    2 : 2
    3 : 3
    ======================
    a : aa
    b : bb
    ======================
  • Array indexes can be numbers, strings, or values of any other type, but the value cannot be nil. Use square brackets [] or . to index a table.

    tbl3 = {}
    tbl3.first = "first1"
    tbl3.second = "second2"
    print(tbl3[1])
    print(tbl3.first)
    print(tbl3["second"])
    -- Output
    nil
    first1
    second2
  • Traversal: the default initial index generally starts from 1.

    -- Initialize the table directly
    tbl2 = { "apple", "pear", "orange", "grape" }
    for k, v in pairs(tbl2) do
        print(k .. " : " .. v)
    end
    -- Output
    1 : apple
    2 : pear
    3 : orange
    4 : grape
  • APIs for operating on tables

    chars = { "a", "b", "c" }
    
    -- table->string
    -- Return the concatenated string from the table
    print("concatenated string ", table.concat(chars))
    -- Specify the separator
    print("concatenated string ", table.concat(chars, ", "))
    -- Specify indexes for concatenating the table
    print("concatenated string ", table.concat(chars, ", ", 2, 3))
    print("=================")
    
    -- Insert into table
    -- Insert at the end
    table.insert(chars, "d")
    print("element at index 4 is ", chars[4])
    -- Insert at the key with index 2
    table.insert(chars, 2, "e")
    print("element at index 2 is ", chars[2])
    print("=================")
    
    -- Delete from table
    print("last element is ", chars[5])
    table.remove(chars)
    print("last element after removal is ", chars[5])
    print("=================")
    
    
    -- Sort table
    print("before sorting")
    for k, v in ipairs(chars) do
        print(k, v)
    end
    
    table.sort(chars)
    print("after sorting")
    for k, v in ipairs(chars) do
        print(k, v)
    end
    print("=================")
    
    -- Get table length
    chars[20] = 20
    print(#chars)
    print(table.getn(chars))
    -- When getting the length of a table, whether using # or table.getn, counting stops where the index is interrupted, causing the table length to be obtained incorrectly.
    -- The following method can be used instead:
    local function table_leng(t)
        local leng = 0
        for k, v in pairs(t) do
            leng = leng + 1
        end
        return leng;
    end
    print(table_leng(chars))
    print("=================")

2.6.1. Array

  • The array size is not fixed, and indexes start from 1.
arr = { "aaa", "bbb", "ccc" }
for index = 1, #arr do
    print(arr[index])
end

-- Output
aaa
bbb
ccc
  • Generic for
arr = { "aaa", nil, "ccc" }
for i = 1, #arr do
    print(i, arr[i])
end
print("=============")

for i, v in ipairs(arr) do
    print(i, v)
end

print("=============")

for i, v in pairs(arr) do
    print(i, v)
end

-- Output
1	aaa
2	nil
3	ccc
=============
1	aaa
=============
1	aaa
3	ccc

2.7. userdata

  • User-defined data, usually a type created by C/C++.
  • Data of any C/C++ data type (usually structs and pointers) can be stored in Lua variables and used.

2.8. thread

  • Coroutine.
  • Multiple threads can run at the same time, while only one coroutine can run at any moment, and a coroutine in the running state pauses only when it is suspended.

3. Variables

  • Lua variables have three types: global variables, local variables, and fields in tables.

    • Variables in Lua are all global variables, even inside statement blocks or functions, unless explicitly declared as local with local.
    • The scope of a local variable starts from its declaration and ends at the end of the statement block it belongs to.
    • The default value of variables is nil.
    if true then
        local name = "zsk"
    end
    
    print(name)
    
    
    if true then
        age = 33
    end
    print(age)
    
    -- Output
    nil
    33
  • Multiple variables can be assigned at the same time.

x, y = 1, 2
x, y = y, x                     -- swap 'x' for 'y'
print(x, y) -- 2 1

-- number of variables > number of values             fill with nil according to the number of variables
a, b, c = 0, 1
print(a, b, c)             --> 0   1   nil

-- number of variables < number of values             extra values are ignored
a, b = 1, 2, 3
print(a, b)               --> 1   2

4. Comments

-- Single-line comment

--[[
Multiline comment
--]]

5. Operators

5.1. Assignment Operators

a, b = 10, 20

c, d, e = 1, 2
str = "hello" .. "world"
print(a, b, c, d, e, str)

-- Output
10	20	1	2	nil	helloworld

5.2. Arithmetic Operators

+ addition
- subtraction
* multiplication
/ division
% remainder
^ exponentiation
- negation

5.3. Relational Operators

== equal to
~= not equal to
> greater than
< less than
>= greater than or equal to
<= less than or equal to

5.4. Logical Operators

  • and: logical AND operator
  • or: logical OR operator
  • not: logical NOT operator
if true and true then
   print(true)
end

if true or false then
    print(true)
end

if not name then
    print(true)
end
-- Output
true
true
true

5.5. Other Operators

  • .. concatenates two strings.
  • # is a unary operator that returns the length of a string or table.
str="hello".."world" -- helloworld
print(#str)-- gets 10

6. Control Flow

6.1. Conditions

local name
if not name then
    print("name is nil")
    name = "test"
end
if name ~= nil then
    print(name)
end

6.2. Loops

6.2.1. while Loop

If the specified condition is true, execute the loop.

a = 10
while (a > 0)
do
    print(a)
    a = a - 1
end
-- Output
10
9
8
7
6
5
4
3
2
1

6.2.2. repeat until

Repeat the loop until the specified condition becomes true, then exit.

b = 10
repeat
    print(b)
    b = b - 1
until (b < 1)

-- Output
10
9
8
7
6
5
4
3
2
1

6.2.3. for Loop

  • Normal for
for a = 10, 1, -1 do
    print(a)
end
  • Generic for
ipairs pairs
Same Both can traverse collections (tables, arrays) Both can traverse collections (tables, arrays)
Different Traverses values rather than keys; stops when encountering nil; stops when encountering reverse-order or skipped indexes; stops when encountering strings Traverses all elements, including keys and values; continues when encountering nil

7. Error Handling

7.1. Raise an Error

  • assert assert first checks the first parameter. If there is no problem, assert does nothing; otherwise, assert throws an error using the second parameter as the error message.

    local function add(a, b)
        assert(type(a) == "number", "a is not a number")
        assert(type(b) == "number", "b is not a number")
        return a + b
    end
    add(10)
    -- Output
    lua.exe: module.lua:3: b is not a number
    stack traceback:
    	[C]: in function 'assert'
    	module.lua:3: in function 'add'
    	module.lua:6: in main chunk
    	[C]: ?
  • error

    • error (message [, level])
      • Terminates the function currently being executed and returns the content of message as the error message.
      • The level parameter indicates the location from which the error is obtained:
        • Level=1 [default]: the location where error is called (file + line number).
        • Level=2: points out the function that called the function that calls error.
        • Level=0: do not add error-location information.
      local function add(a, b)
          error("an error occurred", 1)
          return a + b
      end
      add(10)
      -- Output
      lua.exe: module.lua:2: an error occurred
      stack traceback:
      	[C]: in function 'error'
      	module.lua:2: in function 'add'
      	module.lua:5: in main chunk
      	[C]: ?

7.2. Handle Errors

  • pcall

    local function add(a, b)
        error("a+b encountered an error", 1)
        return a + b
    end
    
    if pcall(add, 1, 2) then
        print("no error")
    else
        print("some error")
    end
    -- Output
    some error
  • xpcall As can be seen from the example above, pcall eats the error, which is not good.

    local function add(a, b)
        error("a+b encountered an error", 1)
        return a + b
    end
    
    local function errorHandle()
        print(debug.traceback())
    end
    
    if xpcall(add, errorHandle, 1, 2) then
        print("no error")
    else
        print("some error")
    end
    -- Output
    stack traceback:
    	module.lua:7: in function <module.lua:6>
    	[C]: in function 'error'
    	module.lua:2: in function <module.lua:1>
    	[C]: in function 'xpcall'
    	module.lua:10: in main chunk
    	[C]: ?
    some error

8. Modules

8.1. What They Are

  • Starting from Lua 5.1, Lua added a standard module-management mechanism.

8.2. Why They Are Needed

  • Some common code can be placed in one file and called elsewhere in the form of API interfaces, which helps code reuse and reduces code coupling.

8.3. Usage

  • A Lua module is a table composed of known elements such as variables and functions. Therefore, creating a module is simple: create a table, put the constants and functions that need to be exported into it, and finally return this table.

8.3.1. Example

  • module.lua
-- File name is module.lua
-- Define a module named module
module = {}
 
-- Define a constant
module.constant = "this is a constant"
 
-- Define a function
function module.func1()
    io.write("this is a public function!\n")
end
 
local function func2()
    print("this is a private function!")
end
 
function module.func3()
    func2()
end
 
return module
  • test_module.lua
-- test_module.lua file
-- module refers to module.lua mentioned above
require("module")

print(module.constant)

module.func3()

8.4. Loading Mechanism

  1. Search in the LUA_PATH environment variable.
  2. Search in the LUA_CPATH environment variable.

9. Object-Oriented Programming

-- Metaclass
Rectangle = { area = 0, length = 0, breadth = 0 }

-- Derived-class method new
function Rectangle:new (o, length, breadth)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    self.length = length or 0
    self.breadth = breadth or 0
    self.area = length * breadth;
    return o
end

-- Derived-class method printArea
function Rectangle:printArea ()
    print("rectangle area is ", self.area)
end
-- Create object
r = Rectangle:new(nil, 10, 20)
-- Access property
print(r.length)
-- Access member function
r:printArea()

10. References

Discussion

Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub