LearnLua - 学习笔记

文章目录


工作需要,复习一下 lua (没什么技术含量,都是搬运内容)


安装环境

Lua 环境安装


其他系统嵌入 lua 的方式来使用

如果不使用上面的安装方式,你也可以使用自己编译 lua 源码,并且设置好 lua 的环境变量

但首先,得自己编译出 lua,得到的:三个主要的文件就可以了:

  • lua.exe - 解析器,可以执行文本方式的 lua 脚本,或是执行 luac.exe 编译出来的 lua 逻辑
  • luac.exe - 编译器
  • lua54.dll - 动态链接库 (这里我的是 5.4 版本的)

在这里插入图片描述

你可以把它们嵌入你的系统

如何编译 lua 可以参考前一篇的:Windows 下使用 Mingw32 编译 Lua 5.4 源码


运行 lua

再 window 上打开 CMD/Power Shell

输入:lua “你的lua的文件的路径”

回车,完事

示例

假设有一个 lua 文件 : my_lua_studies.lua

my_lua_studies.lua 的文件 内容:print("Hello World!")

那么打开 CMD/Power Shell 运行输入下面的内容

C:\Users\admin>lua "E:\Work Files\lua studies\my_lua_studies.lua"
Hello World!

Hello world

print("Hello World!")

-- 输出:Hello World!

notes - 注释

-- 测试:单行注释,单行注释格式:--后续字符串都时注释内容
-- 测试:多行注释,多行注释的格式:--[=[这里填写多行注释的内容]=]
--[=[
    this is multi-lines note1~
    this is multi-lines note2~
    this is multi-lines note3~
]=]

io.write - 输出流内容

-- 测试:io.write 的变长参数的输出
io.write("this is string1 content\n", "this is string2 content\n", "this is string3!\n")

--[=[
输出:
this is string1 content
this is string2 content
this is string3!
]=]

string.format - 字符格式化

-- 测试:string.format 类似C/C++的 printf 之类的格式话输出占位符的方式
io.write(string.format("my name is : %s\n", "jave.lin"))

-- 输出:my name is : jave.lin

function - 函数


single-line - function - 单行写法的函数

-- 测试:声明于定义只有一行的方式
function one_line_func() io.write("this is one_line_func output content!") end

-- 输出:this is one_line_func output content!

multi-lines - function - 多行写法的函数

-- 测试:函数声明:function name([args1, arg2, ...]) [function_body] end
function test_func(arg1)
	-- 测试:输出参数
	io.write("___ test_func first output content! Arg1 : ", arg1, "___\n")
end

-- 输出:___ test_func first output content! Arg1 : arg1_content!___

closure - 闭包,匿名函数

-- 测试:函数声明:function name([args1, arg2, ...]) [function_body] end
function test_func(arg1, arg2)
	-- 测试:闭包声明、调用
	function test_nested_func(nested_func_arg)
		io.write(
			"___ test_nested_func output content! nested_func_arg : ", nested_func_arg,
			-- 测试:闭包使用父级函数调用帧数据
			", parent frame arg2 : ", arg2, "\n")
	end
	-- 测试:输出参数
	io.write("___ test_func first output content! Arg1 : ", arg1, "___\n")
	-- 测试:调用闭包
	test_nested_func("nested_func_arg_content!");
end

--[=[
输出:
___ test_func first output content! Arg1 : arg1_content!___
___ test_nested_func output content! nested_func_arg : nested_func_arg_content!, parent frame arg2 : arg2_content!
]=]

variable - 变量

-- 测试:变量
-- 变量赋值就可以创建了,没有创建过的变量,直接使用也不会报错,因为没又创建的变量会得到:nil

define & undef variable - 定义 & 删除定义变量

-- 测试:定义变量
var1 = 1
print(string.format("var1 : %d", var1))

-- 测试:删除变量
var1 = nil
print(var1)
-- io.write("var1 : ", var1) -- 这里会编译报错,因为var1不存在
-- print(string.format("var1 : %d", var1)) -- 这里会编译报错,因为var1不存在

data type - 数据类型

支持的数据类型:

数据类型描述
nil这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。
boolean包含两个值:false和true。
number表示双精度类型的实浮点数
string字符串由一对双引号或单引号来表示
function由 C 或 Lua 编写的函数
userdata表示任意存储在变量中的C数据结构
thread表示执行的独立线路,用于执行协同程序
tableLua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。
-- 测试:数据类型

-- 测试:table 类型
print(type({})) -- table
var_table = { ["key1"] ="value1", key2 = "value2" }
print(type(var_table)) -- table

-- 测试:字符串
print(type("string_content_type")) -- string
print(type(type("s"))) -- string

-- 测试:数值,lua 中,凡是数值,都时 number 类型
-- lua 整数也时 number 类型
-- float 浮点也时 number 类型
print(type(1)) -- number
print(type(1.0)) -- number
number_var = 999
print(type(number_var)) -- number


-- 测试:函数
print(type(print)) -- function
print(type(type)) -- function
func_var = print
print(type(func_var)) -- function

-- 测试:布尔
print(type(true)) -- boolean
bool_var = false
print(type(bool_var)) -- boolean

-- 测试:nil
print(type(nil)) -- nil
nil_var = nil
print(type(nil_var)) -- nil

number 的详细测试

-- 测试:数值
print("testing output number:")
print(type(2)) -- number
print(type(2.2)) -- number
print(type(0.2)) -- number
print(type(2e+1)) -- number
print(type(0.2e-1)) -- number
print(type(7.8263692594256e-06)) -- number

print(2) -- 2
print(2.2) -- 2.2
print(0.2) -- 0.2
print(2e+1) -- 20
print(0.2e-1) -- 0.02
print(7.8263692594256e-06) -- 7.8263692594256e-006

string concat - 字符拼接

-- 测试:string 字符串拼接
print("=== testing string concat ===") -- concat是concatenate(连锁, 连接)的缩写
str1 = "my name is :"
str2 = "jave.lin"
print("str1 .. str2 : ", str1 .. str2) -- str1 .. str2 :  my name is :jave.lin

也可以直接写数值内容,再用 “…” 来拼接,如下:

print(123 .. 456 .. 789) -- 123456789

raw string - 原始 string 字符串的声明(多行字符串声明)

html = [[
<html>
<head></head>
<body>
    <a href="http://www.runoob.com/">菜鸟教程</a>
</body>
</html>
]]
print(html)

以下代码执行结果为:

<html>
<head></head>
<body>
    <a href="http://www.runoob.com/">菜鸟教程</a>
</body>
</html>

get string size - 获取字符串长度

-- 测试:获取 string 长度
print("=== testing get string size ===")
print(string.format("#\"123456789\" : %d", #"123456789")) -- #"123456789" : 9
var_str = "this is my string content."
print(string.format("#var_str : %d", #var_str)) -- #var_str : 26

封装 get_len - 获取元素长度

如果是字符串那么就是获取字符数,如果是 table 就是获取表格类键值对元素数量

print("=== testing get_len(obj) ===")
-- 测试:获取 table 的长度
function strlen(obj) return #obj end
function tbllen(obj)
    local len = 0
    for k, v in pairs(obj) do
        len = len + 1 -- len++,单目运算符都没有?len+=1也不行
    end
    return len
end
function get_len(obj)
    local type_str = type(obj)
    print(string.format("get_len type_str : %s", type_str))

    if (type_str == "string") then
        return strlen(obj)  -- primitive string length - 获取原始字符串的长度
        -- return #obj -- 这个也可以获取,字符串,或是 table 的长度都可以
    elseif (type_str == "table") then
        -- return #obj         -- primitive table length
        -- 如果直接使用 #obj,会导致结果可能不准确,因为 #obj 会以 table 中连续的索引值来统计的,如果中间有不连续的索引值
        -- 则会停止统计,参考:https://www.runoob.com/lua/lua-tables.html
        -- 所以对 table 的元素个数统计,一般可以先去遍历次数
        return tbllen(obj)
    else
        -- local handler = metatable(obj).__len
        local handler = obj.__metatable
        if handler then
            -- call the handler with the operand
            return (handler(obj))
        else
            error(string.format("get_len(obj) unknow type_str : %s", type_str))
        end
    end
end

local obj = "this is my testing-content"
print(obj)
local var_len = get_len(obj)
print(string.format("get_len(obj) : %d", var_len))

local obj = { ["key1"] = 1, key2 = 2 }
for k, v in pairs(obj) do
    print(string.format("%s=%s, ", k, v))
end
var_len = get_len(obj)
print(string.format("get_len(obj) : %d", var_len))

create table - 创建 table

-- 测试:创建 table
table = { 999, key1 = "value1", key2 = "value2", "not_specify_key_value3", "not_specify_key_value4", 1000 }
for k, v in pairs(table) do
    print(k .. "=" .. v)
end

--[=[
输出:
=== testing table ===
1=999
2=not_specify_key_value3
3=not_specify_key_value4
4=1000
key1=value1
key2=value2
]=]

re-set table - 重置 table

print("=== testing reset-table ===\n")
-- 测试:重新赋值 table
table = { 1,3,5,7,9,2,4,6,8,10 }

-- 测试:第一个元素
print("table[0] : ", table[0])
print("table[1] : ", table[1])

-- 测试:最后一个元素
print("table[9] : ", table[9])
print("table[10] : ", table[10])

-- 测试:遍历元素
print("iterate talbe :")
for i = 1, 10 do
    io.write(table[i], ", ")
end
io.write("\n")

--[=[
输出:

table[0] :      nil
table[1] :      1
table[9] :      8
table[10] :     10
iterate talbe :
1, 3, 5, 7, 9, 2, 4, 6, 8, 10,
]=]

add/insert table element - 从 table 中添加/插入元素

-- 测试:添加元素
print("insert talbe element table[11] = 11 & table[\"test\"] = \"test\"")
table[11] = 11
table.test = "test"
print("table[11] : ", table[11])
print("table[\"test\"] : ", table["test"])
print("iterate talbe :")
for k, v in pairs(table) do
    io.write(k .. "=" .. v, ", ")
end
io.write("\n")

--[=[
输出:
insert talbe element table[11] = 11 & table["test"] = "test"
table[11] :     11
table["test"] :         test
iterate talbe :
1=1, 2=3, 3=5, 4=7, 5=9, 6=2, 7=4, 8=6, 9=8, 10=10, 11=11, test=test,
]=]

remove table element - 从 table 中删除元素

-- 测试:删除元素
print("remove talbe element table[11] = nil & table[\"test\"] = nil")
table[11] = nil -- 删除,第11个成员
-- table.11 = nil -- 这种方式也可以吗?不行
table.test = nil -- 删除,名字为 test 的成员
print("iterate talbe :")
for k, v in pairs(table) do
    io.write(k .. "=" .. v, ", ")
end
io.write("\n")

--[=[
输出:
remove talbe element table[11] = nil & table["test"] = nil
iterate talbe :
1=1, 2=3, 3=5, 4=7, 5=9, 6=2, 7=4, 8=6, 9=8, 10=10,
]=]

if statement - if 语句

-- 测试:if 语句
function check_nil(v)
    if (v == nil)
    then
        print("nil")
    else
        print(v)
    end
end

nil_var = nil
check_nil(nil_var) -- 输出:nil

nil_var = "not nil content"
check_nil(nil_var) -- 出书:not nil content

string-operate - 字符串的运算符操作

-- 测试:字符串 元算符 操作
print("=== testing string-operate ===")
print("1" + "9") -- 10
print("3" + 7) -- 10
print(6 + "4") -- 10

print("16" / "4") -- 4
print("4" * "4") -- 16

var1 = "123"
var2 = "10"

print(var1 * var2) -- 1230
print(var1 / var2) -- 12.3

errCode = 999
-- print("error : " + errCode) -- 编译报错

print("error : " .. errCode) -- 应该使用 .. 来拼接字符,输出:error : 999

table.concat to string - 表的元素拼接成字符

print("=== testing table concat ===")

var_table = { "one", "two", "three" }

--[=[
    table.concat (table [, sep [, start [, end]]]):
    concat是concatenate(连锁, 连接)的缩写.
    table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。
]=]

-- 这里 table.concat 函数为了成功执行,避免在此之前创建了一个名字为:table 的变量,否则会找不到 table.concat 函数
print(string.format("after table.concat(var_table) : %s", table.concat(var_table))) -- after table.concat(var_table) : onetwothree
print(string.format("after table.concat(var_table, \",\") : %s", table.concat(var_table, ","))) -- after table.concat(var_table, ",") : one,two,three
print(string.format("after table.concat(var_table, \",\", 2, 3) : %s", table.concat(var_table, ",", 2, 3))) -- after table.concat(var_table, ",", 2, 3) : two,three

table.insert - 表的元素插入

--[=[
    table.insert (table, [pos,] value):
    在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.
]=]

table.insert(var_table, 4, "four")
-- after table.insert(var_table, 2, "four"), var_table[4] : four
print(string.format("after table.insert(var_table, 2, \"four\"), var_table[4] : %s", var_table[4]))
table.insert(var_table, 2, "between_one&two")

-- after table.insert(var_table, 2, "between_one&two"), var_table[2] : between_one&two
print(string.format("after table.insert(var_table, 2, \"between_one&two\"), var_table[2] : %s", var_table[2]))
io.write("var_table : ") 
for k, v in pairs(var_table) do
    io.write(k .. "=" .. v, ", ")
end
io.write("\n") -- var_table : 1=one, 2=between_one&two, 3=two, 4=three, 5=four,
-- 从上面输出结果可以看出,insert会让插入索引值后续的元素都会往后挪动

table.remove - 表的元素删除

可以参考其他博主的:lua – 使用remove删除table数据

总结一个方式:

-- 后从往前删,因为 table.remove 会该表后续索引内容
for i = #arr, 1, -1 do
	if arr[i] == xx then
		- 删除所有元素等于 xx 的
		table.remove(arr, i)
	end
end

下面是之前测试的

print("=== testing table remove ===")

--[=[
    table.remove (table [, pos])
    返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起。
]=]

io.write("before table.remove(var_table) : ")
for k, v in pairs(var_table) do
    io.write(k .. "=" .. v, ", ")
end
io.write("\n") -- before table.remove(var_table) : 1=one, 2=between_one&two, 3=two, 4=three, 5=four,

table.remove(var_table) -- 不指定 pos,默认为-1,即:删除最后一个元素

io.write("after table.remove(var_table) : ")
for k, v in pairs(var_table) do
    io.write(k .. "=" .. v, ", ")
end
io.write("\n") -- after table.remove(var_table) : 1=one, 2=between_one&two, 3=two, 4=three,

table.remove(var_table, 2) -- 指定 删除 pos 为 2 的元素

io.write("after table.remove(var_table, 2) : ")
for k, v in pairs(var_table) do
    io.write(k .. "=" .. v, ", ")
end
io.write("\n") -- after table.remove(var_table, 2) : 1=one, 2=two, 3=three,

table.sort - 表的元素排序

print("=== testing table sort ===")

--[=[
    table.sort (table [, comp])
    对给定的table进行升序排序。
]=]

function var_table_sort_comp_func(a, b)
    return a > b
end

function table_sort_testing_func(comp_func)
    var_table = { 100, 3, 5, 67, 2, 1, 0, 4, 99 }
    io.write("before sort var_table : ")
    for k, v in pairs(var_table) do
        io.write(k .. "=" .. v, ", ")
    end
    io.write("\n")

    if (comp_func)
    then
        table.sort(var_table, comp_func)
    else
        table.sort(var_table)
    end
    
    io.write("after sort var_table : ")
    for k, v in pairs(var_table) do
        io.write(k .. "=" .. v, ", ")
    end
    io.write("\n")
    
    print("=== testing pure string table sort ===")
    
    var_table = { "ff", "asdf", "abc", "cba", "cc1", "cc0", "cc2" }
    io.write("before sort var_table : ")
    for k, v in pairs(var_table) do
        io.write(k .. "=" .. v, ", ")
    end
    io.write("\n")
    
    if (comp_func)
    then
        table.sort(var_table, comp_func)
    else
        table.sort(var_table)
    end
    
    io.write("after sort var_table : ")
    for k, v in pairs(var_table) do
        io.write(k .. "=" .. v, ", ")
    end
    io.write("\n")

    -- print("=== testing mixing number & string table sort ===")

    -- var_table = { 9, "ff", 0, "asdf", -1, "abc", 100, "cba", 18, "cc1", 16, "cc0", 3, "cc2" }
    -- io.write("before sort var_table : ")
    -- for k, v in pairs(var_table) do
    --     io.write(k .. "=" .. v, ", ")
    -- end
    -- io.write("\n")

    -- -- 不能同时排序:字符串 与 数值 的 table
    -- if (comp_func)
    -- then
    --     table.sort(var_table, comp_func)  -- 运行报错:lua: attempt to compare string with number
    -- else
    --     table.sort(var_table)  -- 运行报错:lua: attempt to compare string with number
    -- end
    -- --[=[
    --     lua: attempt to compare string with number
    --     stack traceback:
    --         [C]: in function 'sort'
    --         E:\Work Files\lua studies\my_lua_studies.lua:394: in main chunk
    --         [C]: ?
    -- ]=]

    -- io.write("after sort var_table : ")
    -- for k, v in pairs(var_table) do
    --     io.write(k .. "=" .. v, ", ")
    -- end
    -- io.write("\n")
end

print("=== testing pure number table sort ===")
print("=== table_sort_testing_func() ===")
table_sort_testing_func()
--[=[
    输出:
    === table_sort_testing_func() ===
    before sort var_table : 1=100, 2=3, 3=5, 4=67, 5=2, 6=1, 7=0, 8=4, 9=99,
    after sort var_table : 1=0, 2=1, 3=2, 4=3, 5=4, 6=5, 7=67, 8=99, 9=100,
    === testing pure string table sort ===
    before sort var_table : 1=ff, 2=asdf, 3=abc, 4=cba, 5=cc1, 6=cc0, 7=cc2,
    after sort var_table : 1=abc, 2=asdf, 3=cba, 4=cc0, 5=cc1, 6=cc2, 7=ff,
]=]

print("=== table_sort_testing_func(var_table_sort_comp_func) ===")
table_sort_testing_func(var_table_sort_comp_func)
--[=[
    输出:
    === table_sort_testing_func(var_table_sort_comp_func) ===
    before sort var_table : 1=100, 2=3, 3=5, 4=67, 5=2, 6=1, 7=0, 8=4, 9=99,
    after sort var_table : 1=100, 2=99, 3=67, 4=5, 5=4, 6=3, 7=2, 8=1, 9=0,
    === testing pure string table sort ===
    before sort var_table : 1=ff, 2=asdf, 3=abc, 4=cba, 5=cc1, 6=cc0, 7=cc2,
    after sort var_table : 1=ff, 2=cc2, 3=cc1, 4=cc0, 5=cba, 6=asdf, 7=abc,
]=]



get the address of table - 获取 table 对象的地址

有时候我们需要获取一个 table 的地址来作为一个 map/dictionary 的 key,但是发现 lua 只有 tostring(tbl) 时,才有打印他的地址,所以索性拿这个地址字符串来作为 key 就好了

(当需要底层灵活性的时候,还是得有底层语言会用得比较得心应手)

print("=== testing get the address of table ===")
local tbl = {}
tbl._0xffffff = 99
print("tostring(tbl):" .. tostring(tbl))
print("tbl._0xffffff : " .. tbl._0xffffff)

function GAO(tbl) -- Get the Address Of table
    assert(tbl ~= nil, "GAO(tbl), tbl is nil")
    assert(type(tbl) == "table", "GAO(tbl), tbl is not a table")
	-- return tostring(tbl):gsub("table: ", "", 1)
	-- return "\"" .. string.sub(tostring(tbl), 8) .. "\""
	return string.sub(tostring(tbl), 8)
end

function push_to_recoder(recorder, tbl)
    assert(recorder ~= nil, "push_to_recoder(recorder, tbl), recorder is nil")
    assert(tbl ~= nil, "push_to_recoder(recorder, tbl), tbl is nil")
    assert(type(tbl) == "table", "push_to_recoder(tbl), tbl is not a table")
    recorder["_" .. GAO(tbl)] = tbl
end

function from_recorder(recorder, tbl)
    assert(recorder ~= nil, "from_recorder(recorder, tbl), recorder is nil")
    assert(tbl ~= nil, "from_recorder(recorder, tbl), tbl is nil")
    assert(type(tbl) == "table", "from_recorder(tbl), tbl is not a table")
    return from_recorder_by_tbl_address(recorder, GAO(tbl))
end

function from_recorder_by_tbl_address(recorder, tbl_address)
    assert(recorder ~= nil, "from_recorder_by_tbl_address(recorder, tbl_address), recorder is nil")
    assert(tbl_address ~= nil, "from_recorder_by_tbl_address(recorder, tbl_address), tbl_address is nil")
	return recorder["_" .. tbl_address]
end

local tbl_1 = {}
local tbl_2 = {}
local tbl_3 = {}
local tbl_4 = {}

print("tostring(tbl_1) : " .. tostring(tbl_1))
print("tostring(tbl_1) : " .. "\"" .. string.sub(tostring(tbl_1), 8) .. "\"")

print("tbl_1 address : " .. GAO(tbl_1))
print("tbl_2 address : " .. GAO(tbl_2))
print("tbl_3 address : " .. GAO(tbl_3))
print("tbl_4 address : " .. GAO(tbl_4))

local recorder = {}
push_to_recoder(recorder, tbl_3)

print("GetByGAO(recorder, GAO(tbl_1)) : " .. tostring(from_recorder(recorder, tbl_1)))
print("GetByGAO(recorder, GAO(tbl_2)) : " .. tostring(from_recorder(recorder, tbl_2)))
print("GetByGAO(recorder, GAO(tbl_3)) : " .. tostring(from_recorder(recorder, tbl_3)))
print("GetByGAO(recorder, GAO(tbl_4)) : " .. tostring(from_recorder(recorder, tbl_4)))

--[=[
    输出:
    === testing get the address of table ===
    tostring(tbl):table: 00AE4AF8
    tbl._0xffffff : 99
    tostring(tbl_1) : table: 00AD0488
    tostring(tbl_1) : "00AD0488"
    tbl_1 address : 00AD0488
    tbl_2 address : 00AD04D8
    tbl_3 address : 00AD0118
    tbl_4 address : 00AD0208
    GetByGAO(recorder, GAO(tbl_1)) : nil
    GetByGAO(recorder, GAO(tbl_2)) : nil
    GetByGAO(recorder, GAO(tbl_3)) : table: 00AD0118
    GetByGAO(recorder, GAO(tbl_4)) : nil
]=]

output table properties - 输出表对象的所有属性

再使用 VSC 中的插件:

  • Debugging for Unity
  • EmmyLua

然后 F5,EmmyLua Attach Debug,在选择对应的 Unity.exe 进程来调试后

发现很频繁的导致 Unity 闪退(崩溃)

频繁到什么个程度:几乎100%的程度,很有可能的时我的使用姿势不正确,但是问过其他同学,他们反馈的也时肯定会闪退,所以他们都时使用 lua 中的 log 来打印

那么中 lua 中,最经常使用的就时 table,如何给一个 table 对象打印他的所有的数据呢?

可以参考一下的示例代码:
首先用到了上面的 GAO get the address of table - 获取 table 对象的地址 的功能,

print("=== testing output table properties ===")
function InnerDump(tbl, indent, indent_str, tbl_address_recorder)
    if (tbl_address_recorder == nil) then
        tbl_address_recorder = {}
    end
    indent = indent or 1
    if (indent_str == nil) then
        indent_str = "\t"
    end

    -- 记录一下 address 信息,防止后续无线递归的问题
    push_to_recoder(tbl_address_recorder, tbl)

    local ret_str = string.format("%s{\n", string.rep(indent_str, indent == 0 and indent - 1 or 0))
    for k, v in pairs(tbl) do
        local str
        local type_str = type(v)
        local append_new_line = true
        if (type_str == "boolean") then
            if (v == false) then
                str = k .. " : " .. "false"
            else
                str = k .. " : " .. "true"
            end
            str = str .. ","
        elseif (type_str == "table") then
            local aov = GAO(v)
            -- 这里判断一下,是否之前记录过 address 信息,防止后续无线递归的问题
            if from_recorder_by_tbl_address(tbl_address_recorder, aov) ~= nil then
                -- 如果打印过表 v 的内容
                str = k .. " : is already print :" .. aov
            else
                -- 如果没有打印过表 v 的内容
                append_new_line = false
                str = k .. " : "
                str = str .. InnerDump(v, indent + 1, indent_str, tbl_address_recorder)
                str = str .. ",\n"
            end
        elseif (type_str == "function") then
            -- str = "func : " .. debug.getinfo(1).name -- 这个只是获取当前执行的函数名字
            str = k .. " : " .. tostring(v)
            str = str .. ","
        else
            str = k .. " : " .. v .. ","
        end

        str = string.rep(indent_str, indent) .. str
        if (append_new_line) then
            ret_str = ret_str .. str .. "\n"
        else
            ret_str = ret_str .. str
        end
    end
    ret_str = ret_str .. string.format("%s}", string.rep(indent_str, indent - 1))

    return ret_str
end


function Dump(tbl, indent_str)
    indent_str = indent_str or "  "
    local ao_recorder = {}
    return InnerDump(tbl, 1, indent_str, ao_recorder)
end

local testing_output_properties_tbl =
{
    id = 1,
    label = "test",
    age = 18,
    nested_table= {
        prop1 = 1,
        prop2 = 999.99,
        nested_table_1 = {
            name = "this is nested level 3 property"
        }
    },
    ["level"] = 888888,
    OnLevelUp = function()
        return debug.getinfo(1).name
    end
}

print("print(Dump(debug.getinfo(print), \"  \")):")
print(Dump(debug.getinfo(print), "  "))

print("print(Dump(testing_output_properties_tbl, \"  \")):")
print(Dump(testing_output_properties_tbl, "  "))
--[=[
    输出:
    print(Dump(debug.getinfo(print), "  ")):
    {
      nups : 0,
      what : C,
      func : function: 00C66BC0,
      lastlinedefined : -1,
      source : =[C],
      currentline : -1,
      namewhat : ,
      linedefined : -1,
      short_src : [C],
    }
    print(Dump(testing_output_properties_tbl, "  ")):
    {
      OnLevelUp : function: 00ADA8E8,
      label : test,
      id : 1,
      level : 888888,
      age : 18,
      nested_table : {
        nested_table_1 : {
          name : this is nested level 3 property,
        },
        prop1 : 1,
        prop2 : 999.99,
      },
    }
]=]

condition-statement-like - 类似条件语句的处理

print("=== testing condition-statement-like ===")
-- 测试:条件语句-like 的处理方式
-- 以为我们再使用 C/C++/C# 等语言中
-- 都有:condition_expr ? condition_true_expr : condition_false_expr
-- 再 lua 中,没有这个语法,但是有类似的方式来实现,如下:
-- condition_expr and condition_true_expr or condition_false_expr
local cond = true
print(string.format("Result : %s", cond and "TRUE" or "FALSE")) -- Result : TRUE
cond = false
print(string.format("Result : %s", cond and "TRUE" or "FALSE")) -- Result : FALSE


string split - 字符串分隔

也可以参考有使用正则的方式:Lua按指定字符分隔字符串的3种方法

-- author   : jave.lin
-- file     : testing.lua
-- 目前还不熟悉 lua,如果能有正则表达是来做分隔就通用,很多,但这个算是性能上比较高的方式

print("=== String Split ===\n")
-- 分隔字符串
function strSplit(str, split_str)
    
    local ret = { }
    -- 分隔符的字符长度
    local split_len = string.len(split_str)
    if (split_len == 0 or split_len == nil) then
        ret[1] = str
        return ret
    end
    -- 需要分隔的字符串的长度
    local str_len = string.len(str)
    -- 起始的搜索位置、上次的搜索位置
    local pos = 1, last_pos
    -- 截取起始位置、截取结束位置
    local start_idx, end_idx
    -- 结果 ret 的索引
    local idx = 1

    repeat
        -- 备份:上次的位置
        last_pos = pos
        -- 查找:当前的从上次的搜索位置开始搜索的结果
        pos = string.find(str, split_str, last_pos)
        -- 非nil:说明能找到
        if (pos ~= nil) then 
            start_idx = last_pos
            end_idx = pos - 1
            -- 截取搜索到的分隔内容
            ret[idx] = string.sub(str, start_idx, end_idx)
            -- 打印内容(调试时可以打开)
            print(
                string.format(
                    "start_idx : %d, end_idx : %d, ret[%d]=\"%s\"",
                    start_idx, end_idx, idx, ret[idx]
                )
            )
            -- 表索引+1
            idx         = idx + 1
            -- 给 上次位置 加上分隔符的长度
            last_pos    = last_pos + split_len
            pos         = pos + split_len
        else
            -- 如果找不到分隔符了,并且上次
            if (str_len > last_pos) then

                ret[idx] = string.sub(str, last_pos)

                print(
                    string.format(
                        "start_idx : %d, end_idx : %d, ret[%d]=\"%s\"",
                        last_pos, -1, idx, ret[idx]
                    )
                )
            end
        end
    until pos == nil -- 当已经查找不到分隔符位置时,就退出循环

    return ret
end

do
    local str = "Hello World, I am Jave.Lin!"
    print(string.format("--- str : %s ---", str))
    str_split_ret = strSplit(str, " ")
    for k, v in pairs(str_split_ret) do
        print(k .. " : " .. "\"" .. v .. "\"")
    end

    str = "A B C D E F G"
    print(string.format("--- str : %s ---", str))
    str_split_ret = strSplit(str, " ")
    for k, v in pairs(str_split_ret) do
        print(k .. " : " .. "\"" .. v .. "\"")
    end

    str = "This__is__my__content"
    print(string.format("--- str : %s ---", str))
    str_split_ret = strSplit(str, "__")
    for k, v in pairs(str_split_ret) do
        print(k .. " : " .. "\"" .. v .. "\"")
    end
end

--[=[
    输出:
    === String Split ===

    --- str : Hello World, I am Jave.Lin! ---
    start_idx : 1, end_idx : 5, ret[1]="Hello"
    start_idx : 7, end_idx : 12, ret[2]="World,"
    start_idx : 14, end_idx : 14, ret[3]="I"
    start_idx : 16, end_idx : 17, ret[4]="am"
    start_idx : 19, end_idx : -1, ret[5]="Jave.Lin!"
    1 : "Hello"
    2 : "World,"
    3 : "I"
    4 : "am"
    5 : "Jave.Lin!"
    --- str : A B C D E F G ---
    start_idx : 1, end_idx : 1, ret[1]="A"
    start_idx : 3, end_idx : 3, ret[2]="B"
    start_idx : 5, end_idx : 5, ret[3]="C"
    start_idx : 7, end_idx : 7, ret[4]="D"
    start_idx : 9, end_idx : 9, ret[5]="E"
    start_idx : 11, end_idx : 11, ret[6]="F"
    1 : "A"
    2 : "B"
    3 : "C"
    4 : "D"
    5 : "E"
    6 : "F"
    --- str : This__is__my__content ---
    start_idx : 1, end_idx : 4, ret[1]="This"
    start_idx : 7, end_idx : 8, ret[2]="is"
    start_idx : 11, end_idx : 12, ret[3]="my"
    start_idx : 15, end_idx : -1, ret[4]="content"
    1 : "This"
    2 : "is"
    3 : "my"
    4 : "content"
]=]

unfixed-len args - 不定长的参数

print("=== testing unfixed-len args ===")
function testing_unfixed_len_arg(arg1, ...)
    print(arg1, ...)
end
testing_unfixed_len_arg("title", 1, 2, true, false, "testing")

--[=[
	输出:
	=== testing unfixed-len args ===
	title   1       2       true    false   testing
]=]


fixed-value in for loop - for i=0, 10 的遍历固定值

print("=== testing table.remove(item, i) in loop ===")
function testing_tbl_remove_item()
    local tbl = {}
    for i=1, 10 do
        tbl[i] = i * 10
    end

    print("testing remove tbl data:")
    for i = 1, 10 do
        print(string.format("tbl[%d]=%d", i, tbl[i]))
    end

    print("testing remove method 1:")

    for i=1, #tbl do
        if (tbl[i] ~= nil) then
            print(string.format("tbl[%d]=%d", i, tbl[i]))
            if (tbl[i] == 50) then
                print(string.format("remove tbl[%d]=%d", i, tbl[i]))
                table.remove(tbl, i)
                print("i:",i)
                -- 这里修改了 i 也没用,因为 for 循环前就保存好了 i 的循环值
                -- 所以下次的 i 还是 6
                i = i - 1
                print("i:",i)
            end
        end
    end

    -- 补回:tbl[5]
    print("recovery tbl[5] = 50:")
    table.insert(tbl, 5, 50)
    for i = 1, #tbl do
        print(string.format("tbl[%d]=%d", i, tbl[i]))
    end
    print("testing remove method 2:")
    local i = 1
    repeat
        if (tbl[i] == 50) then
            print(string.format("remove tbl[%d]=%d", i, tbl[i]))
            table.remove(tbl, i)
        else
            print(string.format("tbl[%d]=%d", i, tbl[i]))
            i = i + 1
        end
        
    until i > #tbl
end
testing_tbl_remove_item()

--[=[
	输出
	=== testing table.remove(item, i) in loop ===
	testing remove tbl data:
	tbl[1]=10
	tbl[2]=20
	tbl[3]=30
	tbl[4]=40
	tbl[5]=50
	tbl[6]=60
	tbl[7]=70
	tbl[8]=80
	tbl[9]=90
	tbl[10]=100
	testing remove method 1:
	tbl[1]=10
	tbl[2]=20
	tbl[3]=30
	tbl[4]=40
	tbl[5]=50
	remove tbl[5]=50
	i:      5
	i:      4
	tbl[6]=70
	tbl[7]=80
	tbl[8]=90
	tbl[9]=100
	recovery tbl[5] = 50:
	tbl[1]=10
	tbl[2]=20
	tbl[3]=30
	tbl[4]=40
	tbl[5]=50
	tbl[6]=60
	tbl[7]=70
	tbl[8]=80
	tbl[9]=90
	tbl[10]=100
	testing remove method 2:
	tbl[1]=10
	tbl[2]=20
	tbl[3]=30
	tbl[4]=40
	remove tbl[5]=50
	tbl[5]=60
	tbl[6]=70
	tbl[7]=80
	tbl[8]=90
	tbl[9]=100
	]=]

no arg func, but call with args - 无参数的函数,但调用时带上参数

说实话,这个也能正常运行,真的很不习惯,-_-!

print("=== testing no arg func, but call with args ===")
function no_arg_func()
    print("no_arg_func")
end
no_arg_func(1,2,3)

--[=[
	输出:
	=== testing no arg func, but call with args ===
	no_arg_func	
]=]

assert - 断言

print("=== testing assert ===")
-- lua 也有 assert 断言
-- 但时断言会中断执行,类似异常,所以下面 assert(true) 不会有输出
-- assert(false, "this is assert(false) output the content")
-- assert(true, msg) 时,msg 是不会输出内容的
assert(true, "this is assert(true), never output the content")

--[=[
    输出:
    === testing assert ===
]=]

testing func self - 方法调用时的 self(语法糖)

这里主要留意:tbl.methodtbl:method 的区别:一个是用 “.”,一个是用 “:” 的区别,本质上是同样的,后者 “:” 只是一个语法糖

tbl.method 的方式定义的参数有多少个,那么再调用时,就传多少个
tbl:method 的方式定义的参数有多少个,调用时,可能需要有些注意的地方

tbl.method 再一般调用时:tbl.method() 就好了,在回调时:addListener(obj, tbl:method) 那就需要注意 这个 method() 第一个参数是需要有 (self) 的,后续添加的参数在 self 后出现

print("=== testing func self ===")
local tbl = { name = "tbl_name"}
function tbl.method1(self)
    print("tbl.method1 self             :", self, "name:", self.name)
end
function tbl:method2(tbl_self)
    print("tbl:method2 tbl_self         :", self, "name:", tbl_self.name)
    print("tbl:method2 self == tbl_self :", self == tbl_self)
end
function tbl:method3()
    print("tbl:method3 self             :", self, "name:", self.name)
end
tbl.method1(tbl)
tbl:method2(tbl) -- 这里就相当于 tbl.method2(tbl, tbl),就是一个语法糖
tbl:method3() -- 这里就相当于 tbl.method3(tbl),就是一个语法糖

--[=[
    输出:
    === testing func self ===
    tbl.method1 self             :  table: 00E34430 name:   tbl_name
    tbl:method2 tbl_self         :  table: 00E34430 name:   tbl_name
    tbl:method2 self == tbl_self :  true
    tbl:method3 self             :  table: 00E34430 name:   tbl_name
]=]

testing bitwise - 测试位操作

print("=== testing bitwise ===")
local bit = require("bit")

--local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex
--local brsh, blsh = bit.rshift, bit.lshift
local a = 1
local b = 3
local c = 2
local d = 16
print("a & b : " .. bit.band(a, b))
print("a | c : " .. bit.bor(a, c))
print("a ^ b : " .. bit.bxor(a, b))
print("tohex(d) : " .. bit.tohex(d))
print("1 << 3 = " .. bit.lshift(1, 3))
print("1 << 0 = " .. bit.lshift(1, 0))
print("3 << 0 = " .. bit.lshift(3, 0))

--[=[
    输出:
    === testing bitwise ===
    a & b : 1
    a | c : 3
    a ^ b : 2
    tohex(d) : 00000010
    1 << 3 = 8
    1 << 0 = 1
    3 << 0 = 3
]=]

testing metatable - 测试元表

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

-- 参考:lua.org 官方的文档(但是很粗率的说明,要了解细节,请看 lua 源码,或时购买相关 lua 的书籍)
-- lua.org 的 Metatables and Metamethods:http://www.lua.org/manual/5.4/manual.html#2.4

-- 参考: class.lua

-- 测试元表
local mtbl = {}
-- '+'
mtbl.__add = function(a, b)
    print(string.format("run the __add: %s:%f + %s:%f = %f", a.name, a.value, b.name, b.value, a.value + b.value))
end
-- '-'
mtbl.__sub = function(a, b)
    print(string.format("run the __sub: %s:%f - %s:%f = %f", a.name, a.value, b.name, b.value, a.value - b.value))
end
-- '*'
mtbl.__mul = function(a, b)
    print(string.format("run the __mul: %s:%f * %s:%f = %f", a.name, a.value, b.name, b.value, a.value * b.value))
end
-- '/'
mtbl.__div = function(a, b)
    print(string.format("run the __div: %s:%f / %s:%f = %f", a.name, a.value, b.name, b.value, a.value / b.value))
end
-- '-n'
mtbl.__unm = function(a)
    print(string.format("run the __unm: -%s:%f = %f", a.name, a.value, -a.value))
end
-- 'idiv'
mtbl.__idiv = function(a, b)
    print(string.format("run the __idiv: %s:%f // %s:%f = %d", a.name, a.value, b.name, b.value, math.floor(a.value / b.value)))
end
-- 'band' 但是外部使用不同对 bit.band(tbl1, tbl2) 处理,只能处理数值,不然会报错
-- 但如果是这样的话,那么提供的这个 __band 原表关键字的设置有何作用?
mtbl.__band = function(a, b)
    local v = bit.band(a.value, b.value)
    print(string.format("run the __band: %s:%f & %s:%f = %d", a.name, a.value, b.name, b.value, v))
    local c = { value = v }
    c.name = a.name .. "_" .. b.name
    return c
end
-- 'bor' 有问题,同上“band”的问题
mtbl.__bor = function(a, b)
    local v = bit.bor(a.value, b.value)
    print(string.format("run the __bor: %s:%f & %s:%f = %d", a.name, a.value, b.name, b.value, v))
    local c = { value = v }
    c.name = a.name .. "_" .. b.name
    return c
end
-- 'bxor' 有问题,同上“band”的问题
mtbl.__bxor = function(a, b)
    local v = bit.bxor(a.value, b.value)
    print(string.format("run the __bxor: %s:%f & %s:%f = %d", a.name, a.value, b.name, b.value, v))
    local c = { value = v }
    c.name = a.name .. "_" .. b.name
    return c
end
-- 'bnot' 有问题,同上“band”的问题
mtbl.__bnot = function(a)
    local v = bit.bnot(a.value)
    print(string.format("run the __bnot: %s:%f = %d", a.name, a.value, v))
    local c = { value = v }
    c.name = a.name
    return c
end
-- 'shl' 有问题,同上“band”的问题
mtbl.__shl = function(a, b)
    local v = bit.shl(a.value, b.value)
    print(string.format("run the __shl: %s:%f & %s:%f = %d", a.name, a.value, b.name, b.value, v))
    local c = { value = v }
    c.name = a.name .. "_" .. b.name
    return c
end
-- 'shr' 有问题,同上“band”的问题
mtbl.__shr = function(a, b)
    local v = bit.shr(a.value, b.value)
    print(string.format("run the __shr: %s:%f & %s:%f = %d", a.name, a.value, b.name, b.value, v))
    local c = { value = v }
    c.name = a.name .. "_" .. b.name
    return c
end
-- 'concat'
mtbl.__concat = function(a, b)
    print(string.format("run the __concat: %s .. %s = %s", a.name, b.name, a.name .. b.name))
    return a.name .. "_" .. b.name
end
-- 'len' -- 这个有点奇怪,外部调用设置过 tbl 的元表的 __len 了,但是再 #tbl 时,还时不会调用 __len 元表的函数
mtbl.__len = function(a)
    local len = strlen(a.name)
    print(string.format("run the __len(%s) = %d", a.name, len))
    return len
end
-- 'eq'
mtbl.__eq = function(a, b)
    local ret = a.value == b.value
    print(string.format("run the __eq {name=%s, value=%d} == {name=%s, value=%d} : %s", a.name, a.value, b.name, b.value, tostring(ret)))
    return ret
end
-- 'lt'
mtbl.__lt = function(a, b)
    local ret = a.value < b.value
    print(string.format("run the __lt {name=%s, value=%d} < {name=%s, value=%d} : %s", a.name, a.value, b.name, b.value, tostring(ret)))
    return ret
end
-- 'le'
mtbl.__le = function(a, b)
    local ret = a.value <= b.value
    print(string.format("run the __le {name=%s, value=%d} <= {name=%s, value=%d} : %s", a.name, a.value, b.name, b.value, tostring(ret)))
    return ret
end
-- 'index'
mtbl.__index = mtbl

mtbl.name = "mtbl_name"

local a_tbl = {name="a", value=8}
local b_tbl = {name="b", value=3}
-- local c_tbl = a_tbl + b_tbl -- 还没有设置 __add 就使用 + 就会运行错误
-- 所以需要先设置 __add 元表内容
setmetatable(a_tbl, mtbl)
setmetatable(b_tbl, mtbl)
-- local c_tbl = a_tbl + b_tbl
local c_tbl

print("-- +")
c_tbl = a_tbl + b_tbl
c_tbl = b_tbl + a_tbl

print("-- -")
c_tbl = a_tbl - b_tbl
c_tbl = b_tbl - a_tbl

print("-- *")
c_tbl = a_tbl * b_tbl
c_tbl = b_tbl * a_tbl

print("-- /")
c_tbl = a_tbl / b_tbl
c_tbl = b_tbl / a_tbl

print("-- -n")
c_tbl = -a_tbl
c_tbl = -b_tbl

print("-- //")
-- // -- 这个会报错,lua 文档可以这么用,但是测试时有错误的,肯定是我使用姿势部对
-- c_tbl = a_tbl // b_tbl
-- c_tbl = b_tbl // a_tbl
c_tbl = getmetatable(a_tbl).__idiv(a_tbl, b_tbl)
c_tbl = getmetatable(b_tbl).__idiv(b_tbl, a_tbl)

print("-- concat")
print(a_tbl .. b_tbl)

print("-- len")
print("before setting a_tbl.name : " .. a_tbl.name .. ", len : " .. strlen(a_tbl.name))
a_tbl.name = "test"
print("after setting a_tbl.name : " .. a_tbl.name .. ", len : " .. strlen(a_tbl.name))
print("#atbl : " .. #a_tbl)
a_tbl.name = "a"

print("-- eq")
print("before setting a_tbl.name : " .. a_tbl.name .. ", a_tbl.value : " .. tostring(a_tbl.value))
print("before setting b_tbl.name : " .. b_tbl.name .. ", b_tbl.value : " .. tostring(b_tbl.value))

a_tbl.name = "test1"
a_tbl.value = 1

b_tbl.name = "test2"
b_tbl.value = 2

print("after setting a_tbl.name : " .. a_tbl.name .. ", a_tbl.value : " .. tostring(a_tbl.value))
print("after setting b_tbl.name : " .. b_tbl.name .. ", b_tbl.value : " .. tostring(b_tbl.value))

print("a_tbl == b_tbl : " .. tostring(a_tbl == b_tbl))

a_tbl.name = "a"
a_tbl.value = 1
b_tbl.name = "a"
b_tbl.value = 1

print("after setting same-value a_tbl.name : " .. a_tbl.name .. ", a_tbl.value : " .. tostring(a_tbl.value))
print("after setting same-value b_tbl.name : " .. b_tbl.name .. ", b_tbl.value : " .. tostring(b_tbl.value))

print("a_tbl == b_tbl : " .. tostring(a_tbl == b_tbl))

print("-- lt")
print("-- le")
print("before setting a_tbl.name : " .. a_tbl.name .. ", a_tbl.value : " .. tostring(a_tbl.value))
print("before setting b_tbl.name : " .. b_tbl.name .. ", b_tbl.value : " .. tostring(b_tbl.value))

a_tbl.name = "test1"
a_tbl.value = 50
b_tbl.name = "test2"
b_tbl.value = 100

print("after setting a_tbl.name : " .. a_tbl.name .. ", a_tbl.value : " .. tostring(a_tbl.value))
print("after setting b_tbl.name : " .. b_tbl.name .. ", b_tbl.value : " .. tostring(b_tbl.value))

print("a_tbl < b_tbl : " .. tostring(a_tbl < b_tbl))
print("a_tbl > b_tbl : " .. tostring(a_tbl > b_tbl))

a_tbl.value = 100
b_tbl.value = 100

print("after setting same-value a_tbl.name : " .. a_tbl.name .. ", a_tbl.value : " .. tostring(a_tbl.value))
print("after setting same-value b_tbl.name : " .. b_tbl.name .. ", b_tbl.value : " .. tostring(b_tbl.value))

print("a_tbl < b_tbl : " .. tostring(a_tbl < b_tbl))
print("a_tbl > b_tbl : " .. tostring(a_tbl > b_tbl))
print("a_tbl <= b_tbl : " .. tostring(a_tbl <= b_tbl))
print("a_tbl == b_tbl : " .. tostring(a_tbl == b_tbl))

print("rawget(a_tbl, \"name\"):", rawget(a_tbl, "name"))
print("rawget(b_tbl, \"name\"):", rawget(b_tbl, "name"))

print(Dump(a_tbl))
print(Dump(getmetatable(a_tbl)))

--[=[
    输出:
    === metatable ===
    -- +
    run the __add: a:8.000000 + b:3.000000 = 11.000000
    run the __add: b:3.000000 + a:8.000000 = 11.000000
    -- -
    run the __sub: a:8.000000 - b:3.000000 = 5.000000
    run the __sub: b:3.000000 - a:8.000000 = -5.000000
    -- *
    run the __mul: a:8.000000 * b:3.000000 = 24.000000
    run the __mul: b:3.000000 * a:8.000000 = 24.000000
    -- /
    run the __div: a:8.000000 / b:3.000000 = 2.666667
    run the __div: b:3.000000 / a:8.000000 = 0.375000
    -- -n
    run the __unm: -a:8.000000 = -8.000000
    run the __unm: -b:3.000000 = -3.000000
    -- //
    run the __idiv: a:8.000000 // b:3.000000 = 2
    run the __idiv: b:3.000000 // a:8.000000 = 0
    -- concat
    run the __concat: a .. b = ab
    a_b
    -- len
    before setting a_tbl.name : a, len : 1
    after setting a_tbl.name : test, len : 4
    #atbl : 0
    -- eq
    before setting a_tbl.name : a, a_tbl.value : 8
    before setting b_tbl.name : b, b_tbl.value : 3
    after setting a_tbl.name : test1, a_tbl.value : 1
    after setting b_tbl.name : test2, b_tbl.value : 2
    run the __eq {name=test1, value=1} == {name=test2, value=2} : false
    a_tbl == b_tbl : false
    after setting same-value a_tbl.name : a, a_tbl.value : 1
    after setting same-value b_tbl.name : a, b_tbl.value : 1
    run the __eq {name=a, value=1} == {name=a, value=1} : true
    a_tbl == b_tbl : true
    -- lt
    -- le
    before setting a_tbl.name : a, a_tbl.value : 1
    before setting b_tbl.name : a, b_tbl.value : 1
    after setting a_tbl.name : test1, a_tbl.value : 50
    after setting b_tbl.name : test2, b_tbl.value : 100
    run the __lt {name=test1, value=50} < {name=test2, value=100} : true
    a_tbl < b_tbl : true
    run the __lt {name=test2, value=100} < {name=test1, value=50} : false
    a_tbl > b_tbl : false
    after setting same-value a_tbl.name : test1, a_tbl.value : 100
    after setting same-value b_tbl.name : test2, b_tbl.value : 100
    run the __lt {name=test1, value=100} < {name=test2, value=100} : false
    a_tbl < b_tbl : false
    run the __lt {name=test2, value=100} < {name=test1, value=100} : false
    a_tbl > b_tbl : false
    run the __le {name=test1, value=100} <= {name=test2, value=100} : true
    a_tbl <= b_tbl : true
    run the __eq {name=test1, value=100} == {name=test2, value=100} : true
    a_tbl == b_tbl : true
    rawget(a_tbl, "name"):  test1
    rawget(b_tbl, "name"):  test2
    {
      name : test1,
      value : 100,
    }
    {
      __shr : function: 00A1A9A8,
      __eq : function: 00A1A868,
      __mul : function: 00A1AC28,
      __bnot : function: 00A1ABA8,
      __le : function: 00A1AA88,
      __band : function: 00A1A8A8,
      __unm : function: 00A1A8C8,
      __len : function: 00A1AA08,
      __index : is already print :00A2C3F0
      __lt : function: 00A1A908,
      __bor : function: 00A1AA48,
      __add : function: 00A1A6E8,
      __div : function: 00A1AB08,
      name : mtbl_name,
      __concat : function: 00A1A9E8,
      __shl : function: 00A1AC48,
      __idiv : function: 00A1AC08,
      __sub : function: 00A1AA68,
      __bxor : function: 00A1AB48,
    }
]=]

testing metatable-__index - 测试元表的 __index

-- 因为 metatable 的测试内容有点多,多是将一些比较大块的内容分开来测试
print("=== testing metatable-__index ===")
local mtbl_human = {}
mtbl_human.value0 = -1

local mtbl_father = {}
mtbl_father.value1 = 100

local mtbl_son = {}
mtbl_son.value2 = 99

print("mtbl_human : " .. Dump(mtbl_human))
print("mtbl_father : " .. Dump(mtbl_father))
print("mtbl_son : " .. Dump(mtbl_son))

setmetatable(mtbl_father, mtbl_human)
setmetatable(mtbl_son, mtbl_father)

print("setmetatable(mtbl_father, mtbl_human)")
print("setmetatable(mtbl_son, mtbl_father)")

print("mtbl_son.value0 = " .. tostring(mtbl_son.value0)) -- mtbl_son.value0 = nil
print("mtbl_son.value1 = " .. tostring(mtbl_son.value1)) -- mtbl_son.value1 = nil
print("mtbl_son.value2 = " .. tostring(mtbl_son.value2))

mtbl_father.__index = mtbl_father

print("after mtbl_father.__index = mtbl_father")

print("mtbl_son.value0 = " .. tostring(mtbl_son.value0)) -- mtbl_son.value0 = nil
print("mtbl_son.value1 = " .. tostring(mtbl_son.value1)) -- mtbl_son.value1 = 100
print("mtbl_son.value2 = " .. tostring(mtbl_son.value2))

mtbl_human.__index = mtbl_human

print("after mtbl_human.__index = mtbl_human")

print("mtbl_son.value0 = " .. tostring(mtbl_son.value0)) -- mtbl_son.value0 = -1
print("mtbl_son.value1 = " .. tostring(mtbl_son.value1)) -- mtbl_son.value1 = 100
print("mtbl_son.value2 = " .. tostring(mtbl_son.value2))

-- 所以 __index 可以理解为是一个索引表,用于 table 的元表数据查找用的
-- 可以用于再 lua 中实现 类似面向对象的功能(OOP)
-- 如果有一个 local derive = { f2 = 1},它只有一个字段:derive.f2
-- 但是如果他要继承 local base = { f1 = 0 },那么想要 derive.f1 也有数值,可以这么处理
-- setmetatable(derive, base)
-- 但是光设置 metatable 还不行
-- 还要 base 对象要有 __index 索引表对象
-- __index 可以设置为 table 或是 function ,这里我们演示 table 的方式
-- 所以需要再加上一句:base.__index = base
-- 就是将 base.__index 提供给使用 base 作为元表查询字段用的,这里指定为 base 本身即可,意思在 base 上去找字段
-- 如果我们的 base 还有基类,如: local base_cls = { f0 = -1 }
-- 然后再 setmetatable(base, base_cls),这样, derive 就可以访问到:f1, f0 字段
-- 因为 元表的 __index 可用于递归查找字段

而获取 lua 中的 table 的某个字段的值它是类似于下面伪代码的处理:

– 元表 __index 设置于使用类型一下伪代码:

setmetatable(tbl, metatable_data) -- 类似于

function setmetatable(tbl, data)
    tbl.__metatable_data = data
end

function get_field(obj, name)
    -- 先再 obj 中查表
    local ret = obj[name]
    -- 如果再 obj 中找不到
    if ret == nil then
        -- 如果有元表数据
        if obj["__metatable_data"] ~= nil
        -- 并且有 __index 索引字段对象
        and obj["__metatable_data"]["__index"] ~= nil
        then
            -- 那么递归 __metatable_data 内的 __index 来查找 name 字段
            ret = get_field(obj["__metatable_data"]["__index"], name)
        end
    end
    return ret
end

local tbl = {}
-- mtble ⇒ metatable
-- 并添加一个字段 field1
local mtbl = {field1=100}
-- 给元表设置 __index 索引对象
mtbl.__index = mtbl
-- 给 tbl 的元表数据设置为 mtbl 对象
setmetable(tbl, mtbl)
-- 获取字段
get_field(tbl, "field1") -- 相当于 lua 的 tbl.field1 或是 tbl["field1"] 的方式

testing metatable field assigment - 测试元表字段的赋值

延续上面的测试

从下面的测试可以发现,原表之间的值只是可以项目独立存在的

print("=== testing metatable field assigment ===")
-- 测试元表的字段赋值
local mtbl_human = {}
mtbl_human.value0 = -1

local mtbl_father = {}
mtbl_father.value1 = 100

local mtbl_son = {}
mtbl_son.value2 = 99

print("mtbl_human : " .. Dump(mtbl_human))
print("mtbl_father : " .. Dump(mtbl_father))
print("mtbl_son : " .. Dump(mtbl_son))

setmetatable(mtbl_father, mtbl_human)
setmetatable(mtbl_son, mtbl_father)

print("setmetatable(mtbl_father, mtbl_human)")
print("setmetatable(mtbl_son, mtbl_father)")

print("mtbl_son.value0 = " .. tostring(mtbl_son.value0)) -- mtbl_son.value0 = nil
print("mtbl_son.value1 = " .. tostring(mtbl_son.value1)) -- mtbl_son.value1 = nil
print("mtbl_son.value2 = " .. tostring(mtbl_son.value2))

mtbl_father.__index = mtbl_father

print("after mtbl_father.__index = mtbl_father")

print("mtbl_son.value0 = " .. tostring(mtbl_son.value0)) -- mtbl_son.value0 = nil
print("mtbl_son.value1 = " .. tostring(mtbl_son.value1)) -- mtbl_son.value1 = 100
print("mtbl_son.value2 = " .. tostring(mtbl_son.value2))

mtbl_human.__index = mtbl_human

print("after mtbl_human.__index = mtbl_human")

print("mtbl_son.value0 = " .. tostring(mtbl_son.value0)) -- mtbl_son.value0 = -1
print("mtbl_son.value1 = " .. tostring(mtbl_son.value1)) -- mtbl_son.value1 = 100
print("mtbl_son.value2 = " .. tostring(mtbl_son.value2))

mtbl_son.value0 = 888
mtbl_son.value1 = 88
mtbl_son.value2 = 8

print("mtbl_human.value0 = " .. tostring(mtbl_human.value0)) -- mtbl_human.value0 = -1
print("mtbl_father.value1 = " .. tostring(mtbl_father.value1)) -- mtbl_father.value1 = -1
print("mtbl_son.value0 = " .. tostring(mtbl_son.value0)) -- mtbl_son.value0 = -1
print("mtbl_son.value1 = " .. tostring(mtbl_son.value1)) -- mtbl_son.value1 = 100
print("mtbl_son.value2 = " .. tostring(mtbl_son.value2))

mtbl_human.value0 = -8
mtbl_father.value1 = -88

print("mtbl_human.value0 = " .. tostring(mtbl_human.value0)) -- mtbl_human.value0 = -8
print("mtbl_father.value1 = " .. tostring(mtbl_father.value1)) -- mtbl_father.value1 = -88
print("mtbl_son.value0 = " .. tostring(mtbl_son.value0)) -- mtbl_son.value0 = -1
print("mtbl_son.value1 = " .. tostring(mtbl_son.value1)) -- mtbl_son.value1 = 100
print("mtbl_son.value2 = " .. tostring(mtbl_son.value2))


--[=[
    输出:
    mtbl_human : {
      value0 : -1,
    }
    mtbl_father : {
      value1 : 100,
    }
    mtbl_son : {
      value2 : 99,
    }
    setmetatable(mtbl_father, mtbl_human)
    setmetatable(mtbl_son, mtbl_father)
    mtbl_son.value0 = nil
    mtbl_son.value1 = nil
    mtbl_son.value2 = 99
    after mtbl_father.__index = mtbl_father
    mtbl_son.value0 = nil
    mtbl_son.value1 = nil
    mtbl_son.value2 = 99
    after mtbl_human.__index = mtbl_human
    mtbl_son.value0 = nil
    mtbl_son.value1 = nil
    mtbl_son.value2 = 99
    mtbl_human.value0 = -1
    mtbl_father.value1 = 100
    mtbl_son.value0 = 888
    mtbl_son.value1 = 88
    mtbl_son.value2 = 8
    mtbl_human.value0 = -8
    mtbl_father.value1 = -88
    mtbl_son.value0 = 888
    mtbl_son.value1 = 88
    mtbl_son.value2 = 8
]=]


string match pattern - 正则字符匹配

因为单篇博客太长,会很卡,所以分在另一篇博客来写了:在 lua 中的正则简单使用


Path Util 类似:C# Path - 获取目录,文件名,扩展名

参考:https://blog.csdn.net/langeldep/article/details/8455783

--获取路径
function LuaUtil.GetDir(filename)
	return string.match(filename, "(.+)/[^/]*%.%w+$") --*nix system
	--return string.match(filename, “(.+)\\[^\\]*%.%w+$”) — windows
end

--获取文件名
function LuaUtil.GetFileName(filename)
	return string.match(filename, ".+/([^/]*%.%w+)$") -- *nix system
	--return string.match(filename, “.+\\([^\\]*%.%w+)$”) — *nix system
end

--去除扩展名
function LuaUtil.StripExtension(filename)
	local idx = filename:match(".+()%.%w+$")
	if(idx) then
		return filename:sub(1, idx-1)
	else
		return filename
	end
end

--获取扩展名
function LuaUtil.GetExtension(filename)
	return filename:match(".+%.(%w+)$")
end

--获取纯文件名
function LuaUtil.GetPureFileName(filename)
	local ret1 = LuaUtil.GetFileName(filename)
	return LuaUtil.StripExtension(ret1)
end

--[=[
local paths = "/use/local/openresty/nginx/movies/fffff.tar.gz"
print (LuaUtil.GetDir(paths))
print (LuaUtil.GetFileName(paths))
print (LuaUtil.StripExtension(paths))
print (LuaUtil.GetExtension(paths))

lua testfile.lua 
/use/local/openresty/nginx/movies
fffff.tar.gz
/use/local/openresty/nginx/movies/fffff.tar
gz

]=]

string StartWith, EndWith - 首位字符串匹配

参考:https://blog.csdn.net/zhangdell/article/details/16833373

function LuaUtil.StartWith(str, substr)  
	if str == nil or substr == nil then  
		return nil, "the string or the sub-stirng parameter is nil"  
	end  
	if string.find(str, substr) ~= 1 then  
		return false  
	else  
		return true  
	end  
end

hex to str, str to hex - 16进制的数值和字符串之间转换

-- hex value
local val = 0xff
print("hex value val : " .. val) -- hex value val : 255

-- hex str to number
local val2 = tonumber("0x" .. "f")
print("hex str to number val2 : " .. val2) -- hex str to number val2 : 15

-- hex number to str
local val3 = 0xffff
print(string.format("hex number to str : %#x", val3)) -- hex number to str : 0xffff



Stack - 栈结构封装

print("start")

local Stack = {}

function Stack:ctor()
	self.count = 0
	self.tbl = {}
end

function Stack:Push(element)
	self.count = self.count + 1
	self.tbl[self.count] = element
	local str = "after Push[" .. self.count .. "] : " .. tostring(element) .. ", "
	for i=1, self.count do
		str = str .. "stack[" .. i .. "]=" .. tostring(self.tbl[i]) .. ","
	end
	print(str)
end

function Stack:Pop()
	if self.count > 0 then
		local ret = self.tbl[self.count]
		self.tbl[self.count] = nil
		local str = "after Pop[" .. self.count .. "] : " .. tostring(ret) .. ", "
		self.count = self.count - 1
		for i=1, self.count do
			str = str .. "stack[" .. i .. "]=" .. tostring(self.tbl[i]) .. ","
		end
		print(str)
		return ret
	end
	return nil
end

function Stack:Empty()
	return self.count == 0
end

function Stack:Clear()
	for i=1, self.count do
		self.tbl[i] = nil
	end
	self.count = 0
end

-- test
Stack:ctor()
print("Stack:ctor()")
print("Stack:Empty():" .. tostring(Stack:Empty()))

print("Stack:Push start")
Stack:Push(1)
Stack:Push(3)
Stack:Push(5)

print("Stack:Pop start")
while Stack:Empty() == false do
	print("Stack:Pop():" .. tostring(Stack:Pop()))
end

print("Stack:Push start")
Stack:Push(2)
Stack:Push(4)
Stack:Push(6)

print("Stack:Clear()")
Stack:Clear()


print("Stack:Empty():" .. tostring(Stack:Empty()))

print("end")


--[=[
start
Stack:ctor()
Stack:Empty():true
Stack:Push start
after Push[1] : 1, stack[1]=1,
after Push[2] : 3, stack[1]=1,stack[2]=3,
after Push[3] : 5, stack[1]=1,stack[2]=3,stack[3]=5,
Stack:Pop start
after Pop[3] : 5, stack[1]=1,stack[2]=3,
Stack:Pop():5
after Pop[2] : 3, stack[1]=1,
Stack:Pop():3
after Pop[1] : 1, 
Stack:Pop():1
Stack:Push start
after Push[1] : 2, stack[1]=2,
after Push[2] : 4, stack[1]=2,stack[2]=4,
after Push[3] : 6, stack[1]=2,stack[2]=4,stack[3]=6,
Stack:Clear()
Stack:Empty():true
end
]=]

table.fromat- 格式化 table 数据

--[[
    @desc: 可替换包含{xxx}的内容
    author: jave.lin
    time:2020-12-09 14:30:58
    --@format_str: 带占位格式的字符串 "{year}-{month}-{day} {hour}:{min}:{sec}"
	--@tbl: 包含{xxx}的内容:{ year = 2020, month = 12, day = 9, hour = 14, min = 30, sec = 58}
	--@p: nil or "{(%w+)}
    @return: 替换了 {xxx} 的内容
]]
table.format = function(format_str, tbl, p)
	p = p or "{(%w+)}"
	return tostring(string.gsub(format_str, p, tbl))
end

测试

-- author	:	jave.lin
-- descript :	测试 os.time, os.date, 还有打印时间格式数据

local now_tick = os.time()
print("now_tick : " .. tostring(now_tick))

local now_date_tbl = os.date("*t", now_tick)
local now_date_str = ""
for k, v in pairs(now_date_tbl) do
	now_date_str = now_date_str .. tostring(k) .. "=" .. tostring(v) .. ","
end
print("now_date_str : " .. now_date_str)

local now_date_format_str = string.format(
	"%d 年 %d 月 %d 日 %d 时 %d 分 %d 秒",
	now_date_tbl.year,
	now_date_tbl.month,
	now_date_tbl.day,
	now_date_tbl.hour,
	now_date_tbl.min,
	now_date_tbl.sec)
print("now_date_format_str : " .. now_date_format_str)

-- {test} 是故意不被替换的一个格式
local date_format_str = "{year}-{month}-{day} {hour}:{min}:{sec} {test}"

local get_date_tbl_field = function(label)
	return tostring(now_date_tbl[label])
end

print("gsub by func : " .. tostring(string.gsub(date_format_str, "{(%w+)}", get_date_tbl_field)))
print("gsub by tbl : " .. tostring(string.gsub(date_format_str, "{(%w+)}", now_date_tbl)))

-- 封装

--[[
    @desc: 可替换包含{xxx}的内容
    author: jave.lin
    time:2020-12-09 14:30:58
    --@format_str: 带占位格式的字符串 "{year}-{month}-{day} {hour}:{min}:{sec}"
	--@tbl: 包含{xxx}的内容:{ year = 2020, month = 12, day = 9, hour = 14, min = 30, sec = 58}
	--@p: nil or "{(%w+)}
    @return: 替换了 {xxx} 的内容
]]
table.format = function(format_str, tbl, p)
	p = p or "{(%w+)}"
	return tostring(string.gsub(format_str, p, tbl))
end

local date_tbl = os.date("*t")
print("DateStr1 : " .. table.format("{month}/{day}/{year} {hour}:{min}:{sec}", date_tbl))
print("DateStr2 : " .. table.format("{year}-{month}-{day} {hour}:{min}:{sec}", date_tbl))

local tbl = {
	act1 = "Tom",
	act2 = "Jerry"
}

print(table.format("{act1} love {act2}", tbl))
print(table.format("{act2} love {act1}", tbl))

local str = table.format("<{act1} and {act2}>", tbl)
print(str)


输出:

now_tick : 1607495817
now_date_str : hour=14,min=36,wday=4,day=9,month=12,year=2020,sec=57,yday=344,isdst=false,
now_date_format_str : 2020129143657 秒
gsub by func : 2020-12-9 14:36:57 nil
gsub by tbl : 2020-12-9 14:36:57 {test}
DateStr1 : 12/9/2020 14:36:57
DateStr2 : 2020-12-9 14:36:57
Tom love Jerry
Jerry love Tom
<Tom and Jerry>

ToLua Call CSharp Callback With Args - ToLua 中调用 csharp 带参数的回调

Lua script

-- 调用 csharp 层的回调
function CallCSCallback(cs_callback, ...)
    if cs_callback ~= nil and cs_callback.DynamicInvoke ~= nil then
        local state_code, error = pcall(cs_callback.DynamicInvoke, cs_callback, ...)
        if state_code == false then
            logError(
                "CallCSCallback state_code : " .. tostring(state_code) ..
                ", error : " .. tostring(error) ..
                ", stacktrace : " .. tostring(debug.traceback())
            )
        end
    end
end

-- call
CallCSCallback(EventMgr.TestCallback)

CSharp callback

[AutoRegistLua]
public class EventMgr
{
	public Action<double> TestCallback;
}

// apply
...
	EventMgr.TestCallback += OnTestCallback;

private void OnTestCallback(double integerID)
{
	// lua 中没有 int, float, double 之分,传到 csharp 都是 double,所以需要转型
   	int integerID_int = (int)integerID;
	Debug.Log($"OnTestCallback integerID_int : {integerID_int }");
}
...

从指定时区提供的时间戳、时区的 UTC 时差,转换为对应当前本地 UTC 时差后的时间

Lua - 从指定时区提供的时间戳、时区的 UTC 时差,转换为对应当前本地 UTC 时差后的时间


显示倒计时


-- author : jave.lin
-- 测试 lua 倒计时
LuaUtil = {}

local DAY_SECS = 60 * 60 * 24
local HOUR_SECS = 60 * 60
local MIN_SECS = 60

function LuaUtil.GetTimeStr(seconds)
    -- local day_secs = 60 * 60 * 24
    -- local day = seconds / day_secs
    -- day = math.floor(day)
    -- seconds = seconds - (day * 24 * 60 * 60)

    -- local hour = math.min(math.floor(seconds / (60 * 60)), 59)
    -- seconds = seconds - (hour * 60 * 60)

    -- local min = math.min(math.floor(seconds / 60), 59)
    -- seconds = seconds - (min * 60)

    -- local sec = seconds % 60
    -- -- seconds = seconds - sec

    -- return string.format("%02dD %02dh %02dm %02ds", day, hour, min, sec)

    -- 优化写法
    local day = math.floor(seconds / DAY_SECS)
    local hour = math.min(math.floor((seconds % DAY_SECS) / HOUR_SECS), 59)
    local min = math.min(math.floor((seconds % HOUR_SECS) / MIN_SECS), 59)
    local sec = seconds % MIN_SECS
    return string.format("%02dD %02dh %02dm %02ds", day, hour, min, sec)
end

function LuaUtil.GetTimeStrNoDay(seconds)
    -- local hour = math.floor(seconds / (60 * 60))
    -- seconds = seconds - (hour * 60 * 60)

    -- local min = math.min(math.floor(seconds / 60), 59)
    -- seconds = seconds - (min * 60)

    -- local sec = seconds % 60
    -- -- seconds = seconds - sec

    -- return string.format("%02dh %02dm %02ds", hour, min, sec)

    -- 优化写法
    local hour = math.min(math.floor((seconds % DAY_SECS) / HOUR_SECS), 59)
    local min = math.min(math.floor((seconds % HOUR_SECS) / MIN_SECS), 59)
    local sec = seconds % MIN_SECS
    return string.format("%02dh %02dm %02ds", hour, min, sec)
end

function ShowDayResetTime()
	local now_tick = os.time()

	local target_date_time_tbl = os.date("*t")
	target_date_time_tbl.hour = 23
	target_date_time_tbl.min = 59
	target_date_time_tbl.sec = 59

	local target_tick = os.time(target_date_time_tbl)

	local seconds = target_tick - now_tick
	print(string.format("DayResetTime : %s", LuaUtil.GetTimeStr(seconds)))
end


function ShowWeekResetTime()
	local now_tick = os.time()

	local target_date_time_tbl = os.date("*t")
	target_date_time_tbl.hour = 23
	target_date_time_tbl.min = 59
	target_date_time_tbl.sec = 59

	local target_tick = os.time(target_date_time_tbl)

	if target_date_time_tbl.wday == 1 then
		-- 周日,不处理
	elseif target_date_time_tbl.wday < 8 then
		-- 周一 ~ 周六
		local plus_day = 8 - target_date_time_tbl.wday
		local plus_seconds = plus_day * 24 * 60 * 60
		target_tick = target_tick + plus_seconds
	end

	local seconds = target_tick - now_tick
	print(string.format("WeekResetTime : %s", LuaUtil.GetTimeStr(seconds)))
end

function print_date_tbl(date_tbl)

	local format_str = string.format(
		"%d 年 %d 月 %d 日 %d 时 %d 分 %d 秒",
		date_tbl.year,
		date_tbl.month,
		date_tbl.day,
		date_tbl.hour,
		date_tbl.min,
		date_tbl.sec)
	print("now_date_format_str : " .. format_str)
end


print_date_tbl(os.date("*t"))

ShowDayResetTime()
ShowWeekResetTime()

输出

now_date_format_str : 202115133722 秒
DayResetTime : 00D 10h 22m 37s
WeekResetTime : 05D 10h 22m 37s

References

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值