您当前的位置: 首页 >  Jave.Lin ar

LearnLua - 学习笔记

Jave.Lin 发布时间:2020-09-13 22:31:44 ,浏览量:4

文章目录
  • 安装环境
  • 其他系统嵌入 lua 的方式来使用
  • 运行 lua
    • 示例
  • Hello world
  • notes - 注释
  • io.write - 输出流内容
  • string.format - 字符格式化
  • function - 函数
    • single-line - function - 单行写法的函数
    • multi-lines - function - 多行写法的函数
  • closure - 闭包,匿名函数
  • variable - 变量
    • define & undef variable - 定义 & 删除定义变量
  • data type - 数据类型
    • number 的详细测试
  • string concat - 字符拼接
  • raw string - 原始 string 字符串的声明(多行字符串声明)
  • get string size - 获取字符串长度
    • 封装 get_len - 获取元素长度
  • create table - 创建 table
  • re-set table - 重置 table
  • add/insert table element - 从 table 中添加/插入元素
  • remove table element - 从 table 中删除元素
  • if statement - if 语句
  • string-operate - 字符串的运算符操作
  • table.concat to string - 表的元素拼接成字符
  • table.insert - 表的元素插入
  • table.remove - 表的元素删除
  • table.sort - 表的元素排序
  • get the address of table - 获取 table 对象的地址
  • output table properties - 输出表对象的所有属性
  • condition-statement-like - 类似条件语句的处理
  • string split - 字符串分隔
  • unfixed-len args - 不定长的参数
  • fixed-value in for loop - for i=0, 10 的遍历固定值
  • no arg func, but call with args - 无参数的函数,但调用时带上参数
  • assert - 断言
  • testing func self - 方法调用时的 self(语法糖)
  • testing bitwise - 测试位操作
  • testing metatable - 测试元表
    • testing metatable-__index - 测试元表的 __index
    • testing metatable field assigment - 测试元表字段的赋值
  • string match pattern - 正则字符匹配
  • Path Util 类似:C# Path - 获取目录,文件名,扩展名
  • string StartWith, EndWith - 首位字符串匹配
  • hex to str, str to hex - 16进制的数值和字符串之间转换
  • Stack - 栈结构封装
  • table.fromat- 格式化 table 数据
      • 测试
  • ToLua Call CSharp Callback With Args - ToLua 中调用 csharp 带参数的回调
    • Lua script
    • CSharp callback
  • 从指定时区提供的时间戳、时区的 UTC 时差,转换为对应当前本地 UTC 时差后的时间
  • 显示倒计时
  • References

工作需要,复习一下 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 = [[



    菜鸟教程


]]
print(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.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
]=]
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             
关注
打赏
1688896170
查看更多评论
0.0675s