工作需要,复习一下 lua (没什么技术含量,都是搬运内容)
Lua 环境安装
如果不使用上面的安装方式,你也可以使用自己编译 lua 源码,并且设置好 lua 的环境变量
但首先,得自己编译出 lua,得到的:三个主要的文件就可以了:
你可以把它们嵌入你的系统
如何编译 lua 可以参考前一篇的:Windows 下使用 Mingw32 编译 Lua 5.4 源码
再 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!
print("Hello World!")
-- 输出:Hello World!
-- 测试:单行注释,单行注释格式:--后续字符串都时注释内容
-- 测试:多行注释,多行注释的格式:--[=[这里填写多行注释的内容]=]
--[=[
this is multi-lines note1~
this is multi-lines note2~
this is multi-lines note3~
]=]
-- 测试: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 类似C/C++的 printf 之类的格式话输出占位符的方式
io.write(string.format("my name is : %s\n", "jave.lin"))
-- 输出:my name is : jave.lin
-- 测试:声明于定义只有一行的方式
function one_line_func() io.write("this is one_line_func output content!") end
-- 输出:this is one_line_func output content!
-- 测试:函数声明: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!___
-- 测试:函数声明: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!
]=]
-- 测试:变量
-- 变量赋值就可以创建了,没有创建过的变量,直接使用也不会报错,因为没又创建的变量会得到:nil
-- 测试:定义变量
var1 = 1
print(string.format("var1 : %d", var1))
-- 测试:删除变量
var1 = nil
print(var1)
-- io.write("var1 : ", var1) -- 这里会编译报错,因为var1不存在
-- print(string.format("var1 : %d", var1)) -- 这里会编译报错,因为var1不存在
支持的数据类型:
数据类型 | 描述 |
---|---|
nil | 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
boolean | 包含两个值:false和true。 |
number | 表示双精度类型的实浮点数 |
string | 字符串由一对双引号或单引号来表示 |
function | 由 C 或 Lua 编写的函数 |
userdata | 表示任意存储在变量中的C数据结构 |
thread | 表示执行的独立线路,用于执行协同程序 |
table | Lua 中的表(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
-- 测试:数值
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 字符串拼接
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
html = [[
菜鸟教程
]]
print(html)
以下代码执行结果为:
<html>
<head>head>
<body>
<a href="http://www.runoob.com/">菜鸟教程a>
body>
html>
-- 测试:获取 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
如果是字符串那么就是获取字符数,如果是 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))
-- 测试:创建 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
]=]
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,
]=]
-- 测试:添加元素
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,
]=]
-- 测试:删除元素
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 语句
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
-- 测试:字符串 元算符 操作
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
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, [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会让插入索引值后续的元素都会往后挪动
可以参考其他博主的: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,
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,
]=]
有时候我们需要获取一个 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
]=]
再使用 VSC 中的插件:
然后 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,
},
}
]=]
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
也可以参考有使用正则的方式: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"
]=]
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
]=]
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
]=]
说实话,这个也能正常运行,真的很不习惯,-_-!
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
]=]
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 ===
]=]
这里主要留意:tbl.method 和 tbl: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
]=]
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
]=]
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,
}
]=]
-- 因为 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"] 的方式
延续上面的测试
从下面的测试可以发现,原表之间的值只是可以项目独立存在的
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
]=]
因为单篇博客太长,会很卡,所以分在另一篇博客来写了:在 lua 中的正则简单使用
参考: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
]=]
参考: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 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
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
]=]
--[[
@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 : 2020 年 12 月 9 日 14 时 36 分 57 秒
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>
-- 调用 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)
[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 }");
}
...
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 : 2021 年 1 月 5 日 13 时 37 分 22 秒
DayResetTime : 00D 10h 22m 37s
WeekResetTime : 05D 10h 22m 37s