Lua基础简介

Lua基础简介

第一个lua程序

--[[这是多行注释]]--
--[[这是多行注释]]
--[[这也是多行注释--]]
--单行注释
print("hello world");

Lua变量

--lua中的语法简介1:
--[[
1. lua可以没有分号结尾,有也不影响。这个看个人习惯了。
2. lua中所有的额变量都不需要声明,直接写变量名就可以用,且变量类型取决于赋值的类型,这一点很像C#中的var。
3. 需要清楚:lua是动态语言,即和javascript一样,虽然变量类型的获取方面很像var但不完全一样。体现在C#中的var类型变量在初始赋值后类型就定死了,而lua中的变量类型可以改变。
4. 对于从未使用过的变量其值为nil,因此可以理解为nil是lua变量的默认值。
5. 变量名、函数名之类的命名规则与C#语言一样:由字母,下划线和数字组成,但第一个字符不能是数字。并且不能和Lua的保留字相同。
6. Lua是大小写敏感的
7. 注意Lua中所有的值都可以作为条件。在控制结构的条件中除了false和nil为假,其他值都为真。所以Lua认为0和空串都是真。
]]

--lua中的四种简单变量类型:
--1. nil,等价于C#中的null,且是变量的默认值
print("*******************");
a = nil;
print(a);
--2. number,等价于C#中的数值类型,在lua中不管是int,long,float,double都是一个类型number
print("*******************");
a = 10;
a = 1.1;
print(a);
--3. string,等价于C#中的string类型,但需要注意lua中是没有char类型的,不论是单引号还是双引号都代表string类型,Lua中字符串是不可以修改的。和C#一样
print("*******************");
a = "tian";
a = 'tian2';
print(a);
--4. boolean,等价于C#中的bool类型
print("*******************");
a = true;
print(a);
--5. type函数,可以返回变量的类型,返回值为string
print("*******************");
print(type(a));

--lua中的四种复杂数据类型:
--1. function:函数
--2. table:表
--3. userdata:数据结构
--4. thread:协同程序

Lua字符串

--1. 获得字符串长度,特别注意中文字符长度为3
print("*********************");
s = "123";
s = "是";
print(#s);
--2. lua支持转义字符
print("*********************");
print("213\n123\tqwe\\");
--3. 字符串多行打印
print("*********************");
s = [[
我
是
tian
]];
print(s);
--[[4. 字符串拼接,简单类型中不能直接拼接nil类型,boolean类型想要拼接这两个类型需要先使用tostring函数将其转换为string在拼接
拼接的结果为string类型,这点和C#很像]]
print("*********************");
print("123" .. "tian" .. tostring(true) .. tostring(nil));
--5. 字符串格式化,其书写方式和C语言很像
print(string.format("我今年%d岁了",18));
--6. lua提供的string方法
print("*********************");
str = "ASDfdsgFGASD";
--小写转大写
print(string.upper(str));
--大写转小写
print(string.lower(str));
--字符串查找,输出的数字是想要查找的字符串在str中的第一个的开头索引和结束索引
--注意lua的索引是从1开始的
print(string.find(str,"ASD"));
--截取字符串
--参数分别为要截取的字符串,开始索引,结束索引
print(string.sub(str, 1,5));
--字符串重复
--参数分别是要重复的字符串,重复次数
print(string.rep(str,2));
--字符串修改
--参数分别是要修改的字符串,要修改的字符,使用什么字符替换
--打印的内容分别是:修改后的字符串,修改的次数
print(string.gsub(str, "ASD", "***"));
--字符串转ASCII码
a = string.byte("Lua",1);
print(a);
--ASCII码转字符串
print(string.char(a));

Lua运算符

--lua运算符
print("*********************");
print("算术运算符");
--算术运算符包括: 加法+ 减法- 乘法* 除法/ 取余% 幂^
print("1加法2" .."\t" .. 1+2);
print("1减法2" .."\t" .. 1-2);
print("2乘法3" .."\t" .. 2*3);
print("4除法2" .."\t" .. 4/2);
print("2幂运算4" .."\t" .. 2^4);
--其中lua幂运算所使用的符号在C#中是异或的符号
--lua没有自增自减运算 ++ --
a = 1;
a = a + 1;
print("lua没有自增自减运算" .. a);
--lua没有快捷运算(混合运算符)+= -=等
b = 2;
a = a + b;
print("lua没有快捷运算(混合运算符)" .. a);
--如果字符串可以转换为number,则也可以参与运算
print("123" + 2);
print("123" * 2);
--需要注意的一点是,在lua中+仅仅有算数功能,没有字符串拼接的功能,想在lua中拼接字符串要使用.. 这一点和C#不同,不要弄混了。
--算数运算符不可运算nil,会报错。

print("*********************");
print("条件运算符");
--条件运算符包括: 大于> 小于< 大于等于>= 小于等于<= 等于== 不等于~=
print("1大于2" .. tostring(1>2));
print("1小于2" .. tostring(1<2));
print("1大于等于2" .. tostring(1>=2));
print("1小于等于2" .. tostring(1<=2));
print("1等于2" .. tostring(1==2));
print("1不等于2" .. tostring(1~=2));
--注意,lua中的条件运算符写法和用法基本和C#一致,不同的是不等于在C#中是!=,而在lua中是~=

print("*********************");
print("逻辑运算符");
--逻辑运算符包括: and or not
--分别对应C#中的&& || !
--lua中的逻辑运算符依然支持短路逻辑运算,对于与运算,第一项为假返回第一项,否则返回第二项;对于或运算,第一项为真返回第一项,否则返回第二项。
--注意Lua中所有的值都可以作为条件。在控制结构的条件中除了false和nil为假,其他值都为真。所以Lua认为0和空串都是真。

--false
print(false and 1);
--2
print(1 and 2);
--nil
print(nil and 1);
--nil
print(0 and nil);
--1
print("" and 1);

print("*********************");
--lua不支持三目运算符和位运算符

Lua条件分支语句

print("*********************");
print("条件分支语句");
--lua条件分支语句和C#中的有很大的不同,lua中需要用if和then将条件包裹
--单分支结构
a = 5;
if a == 5 then 
	print(5);
end

--双分支结构
if a == 5 then 
	print(true);
else
	print(false);
end

--多分枝语句
--lua中的elseif一定要连着写,否则会报错
if a == 1 then 
	print("a是1");
elseif a == 2 then
	print("a是2");
elseif a == 3 then
	print("a是3");
else
	print("other");
end

--lua中没有switch语句,想要使用就需要自己实现

Lua循环语句

print("*********************");
print("while语句");
--while循环
num = 0;
while num < 5 do
	print(num);
	num = num + 1;
end

print("*********************");
print("do while语句");
--do while语句
--注意until写的是结束条件,而不是C#中的循环条件
repeat
	print(num);
	num = num - 1;
until num < 1 --满足条件跳出循环

print("*********************");
print("for语句");
--lua中的for循环会默认自增
for i = 1,5 do
	print(i);
end
print("*********************");
--如果我不想自增1
--三个数字分别为:初始值,结束值,增值
for i = 1,5,2 do
	print(i);
end

Lua函数:function

print("*********************");
print("函数声明");
--[[
方式1: function 函数名()
		end

方式2: temp = function()
		end
]]
function MyFirstFunc( ... )
	-- body
end
temp = function( ... )
	-- body
end


print("*********************");
print("函数 : 无参无返回值");
function MyFirstFunc()
	print("调用函数MyFirstFunc : 无参无返回值的函数");
end
--这种将函数作为值赋值给一个变量的形式很像C#中的回调函数注册
temp = function()
	print("调用函数temp : 无参无返回值的函数");
end
--函数调用
MyFirstFunc();
temp();


print("*********************");
print("函数:有参数");
function FunctionWithVariable(value)
	print("传入的参数为:" .. tostring(value));
end
temp = function(value)
	print("传入的参数为:" .. tostring(value));
end
FunctionWithVariable(true);
temp(123);
--如果你传入的参数个数和函数声明的参数个数不匹配lua会有两种处理方法
--1. 如果传入的参数多于声明的参数个数,lua会丢弃多余的参数
temp(1,2,3,4);
--2. 如果传入的参数少于声明的参数个数,没有得到值的参数为nil
temp();


print("*********************");
print("函数 : 有返回值");
--单返回值
function FunctionWithReturn(value)
	return value;
end
print("返回值为:" .. tostring(FunctionWithReturn(1)));
--多返回值
--[[
多返回值时,在前面声明多个变量来接受即可
如果接受的变量不够,lua会丢弃剩下的返回值
如果接受的变量够且多余返回值的个数,没有得到返回值的变量为nil
]]
function FunctionWithReturn(value)
	return value, true, "123";
end
tempValue1, tempValue2, tempValue3, tempValue4 = FunctionWithReturn(1);
print("接收到的返回值分别为: " .. tostring(tempValue1));
print("接收到的返回值分别为: " .. tostring(tempValue2));
print("接收到的返回值分别为: " .. tostring(tempValue3));
print("接收到的返回值分别为: " .. tostring(tempValue4));

print("*********************");
print("函数类型");
--函数的类型为function
print("函数的类型为: " .. type(FunctionWithReturn));

print("*********************");
print("lua函数不支持函数重载");
--在lua中声明多个相同名称的函数可以调用的之后最后一个
--在lua中函数是可以赋值给变量的一个类型,就和number,string一样
--所以对于lua来说,函数重载的写法就相当于是重新定义赋值了一个函数
function FunctionOverLoad()
	print("重载测试1");
end
function FunctionOverLoad(value)
	print("重载测试2,value为: " .. tostring(value));
end
--执行的第二个函数
FunctionOverLoad();

print("*********************");
print("变长参数");
--默认补全的函数的参数列表中的三个点就是变长参数的符号
function FunctionWithParams( ... )
	--声明一个table保存变长参数,
	paramArray = {...};
	--for循环读取table中的内容
	for i=1,#paramArray do
		print(paramArray[i]);
	end
end
FunctionWithParams(1,2,3,4,5,6,7);

print("*********************");
print("lua函数嵌套");
--闭包,拓展局部变量的生命周期
function FunctionWithSub(value)
	return function(subValue)
		print(tostring(value) + tostring(subValue));
	end
end
--value参数变量的生命周期为FunctionWithSub这个函数
subFunction = FunctionWithSub(2);
--此时的FunctionWithSub函数已经执行结束按理来说value变量失效,
--但是subFunction中引用了value,value在生命周期外被使用,生命周期被拓展
subFunction(3);

Lua使用table模拟数组

print("*********************");
print("table");
--表是一切复杂数据类型的基础,包括:数组,二维数组,字典,类等等
print("*********************");
print("一维数组");
a = {1,2,3,4,"123",true,nil};
b = {1,2,nil,3,nil,"123",true};
print("0号索引:" .. tostring(a[0]));
--注意lua中的索引默认从1开始,除非使用自定义索引
print("1号索引:" .. tostring(a[1]));


print("*********************");
print("一维数组遍历");
print("a数组成员个数:" .. tostring(#a));
for i=1,#a do
	print(a[i]);
end
print("b数组成员个数:" .. tostring(#b));
for i=1,#b do
	print(b[i]);
end
--现象表明lua中,如果table的末尾值为nil则不计算为table长度,可能为bug,日后可能会修改
--旧版lua中中间nil类型会中断#关键字的长度统计

print("*********************");
print("二维数组");
--和C语言的数组形式很像
a = {{1,2,3},{4,5,6}};
print("1,1号索引:" .. tostring(a[1][1]));
print("2,2号索引:" .. tostring(a[2][2]));

print("*********************");
print("二维数组的遍历");

for i=1,#a do
	b = a[i]
	for j=1,#b do
		print(b[j]);
	end
end

print("*********************");
print("自定义索引");
aa = {[0] = 1, 2,3,[-1] = 4,5};
print("0号索引:" .. tostring(aa[0]));
print("-1号索引:" .. tostring(aa[-1]));
--#关键字只会统计>=1的索引
print(#aa);

--lua中的一些bug现象,之后可能会修复
--当使用自定义索引,且间隔为一个数时,#统计出来的为最大索引数
aa = {[1] = 1,[2] = 2, [4] = 4,[6] = 6};
print(#aa);
--当使用自定义索引,且间隔大于一个数时,我称之为索引中断,#统计出来的为数量为中断处的索引数
aa = {[1] = 1,[2] = 2, [5] = 4,[6] = 6};
print(#aa);

Lua迭代器

print("*********************");
print("迭代器遍历");
--迭代器遍历,主要用来遍历表的
--由于#关键字得到的数组长度并不准确,我们一般不用#来遍历表

print("*********************");
print("ipairs迭代器遍历1");
--ipairs
--ipairs遍历和老版#关键字比较像,遇见nil就会停止。
b = {1,2,nil,3,nil,"123",true};
for i,v in ipairs(b) do
	print(i,v);
end

print("*********************");
print("ipairs迭代器遍历2");
--ipairs遍历和#关键字相比依旧是从1开始往后遍历的,小于等于0的索引得不到
a = {[0] = 1, 2,3,[-1] = 4,5};
for i,v in ipairs(a) do
	print(i,v);
end

print("*********************");
print("ipairs迭代器遍历3");
--ipairs遍历只能找到连续的索引,如果索引中断,则ipairs没有办法遍历后面的内容
aa = {[1] = 1,[2] = 2, [4] = 4,[6] = 6};
for i,v in ipairs(aa) do
	print(i,v);
end

--下面介绍pairs迭代器遍历,pairs相比较ipairs很多问题得到了改善
print("*********************");
print("pairs迭代器遍历1");
--pairs迭代器遍历会直接掠过为nil的值,这样就不会像ipairs那样因为nil而中断
b = {1,2,nil,3,nil,"123",true};
for i,v in pairs(b) do
	print(i,v);
end

print("*********************");
print("pairs迭代器遍历2");
--pairs可以找到所有非nil的值
a = {[0] = 1, 2,3,[-1] = 4,5};
for i,v in pairs(a) do
	print(i,v);
end
--[[
总结:
ipairs迭代器遍历和旧版#关键字的效果一样,只适合遍历索引连续且中间没有nil类型,没有自定义索引的table。
pairs迭代器遍历会掠过nil,这样pairs遍历就不会因为nil而终止遍历,而是可以找到table所有的键值。比较通用
]]



Lua使用table模拟字典

print("*********************");
print("使用table实现字典");
print("字典的声明");
--字典是由键值对构成的,我们使用自定义索引来实现字典结构
a = {["name"] = "tian", ["age"] = 14, ["1"] = 1};
--当自定义索引为string时且string不能转换为number类型,则可以通过点修饰符调用对应的值
print("使用点修饰符获得值:" .. tostring(a.name));
print("使用传统方法获得值:" .. tostring(a["name"]));
--如果自定义索引为string且可以转换为number类型就只能通过索引器调用。
print("只能通过索引器调用:" .. tostring(a["1"]));

print("*********************");
print("对字典的一些操作");
--修改字典值,两种方式都可
a["name"] = "修改之后的name1";
print(a["name"]);
a.name = "修改之后的name2";
print(a.name);

--新增字典项,两种方式都可
a["sex1"] = true;
print("新增字典项sex1:" .. tostring(a["sex1"]));
a.sex2 = false;
print("新增字典项sex2:" .. tostring(a.sex2));

--删除字典项,两种方式都可
a["sex1"] = nil;
a.sex2 = nil;
print("字典项sex1被删除:" .. tostring(a["sex1"]));
print("字典项sex2被删除:" .. tostring(a.sex2));

print("*********************");
print("字典遍历");
--如果使用table模拟字典,一定要使用pairs来进行遍历,因为字典中极有可能存在nil类型
for k,v in pairs(a) do
	print(k,v)
end
--关于一种只输出字典值的写法,这里的“_”其实和上面的“k”一样都是一个变量,只不过是打印的时候我们不选择打印键
for _,v in pairs(a) do
	print(v)
end

Lua使用table模拟类和结构体

print("*********************");
print("类和结构体");
--lua中是没有面向对象的,需要我们自己来实现,lua中的类说白了就是一个存放了各种类型的table。
--lua的类在使用的效果上和C#的只有静态成员的静态类很像。
--下面我们声明一个类。
--由于lua中的类本质是一个表,所以成员之间是使用,分隔的。且这个”类“是全局唯一的。
Student = {
	age = 15,
	sex = "男",
	GrowUp = function()
		print("我成长了");
	end,
	Learn = function()
		print("我学习了");
	end,
	MyInfo = function(info)
		print("我的年龄是" .. tostring(info.age) .. "岁");
		print("我的性别是" .. tostring(info.sex));
	end,
}
--除了像上面这样在表内声明变量和函数,我们还可以在表的外部声明。
--表外部声明属性。
Student.name = "tian";
--表外部声明函数,方式1。
Student.Speak = function()
	print("我说话了");
end
--表外部声明函数,方式2。
function Student.Speak2()
	print("我又说话了");
end
print("*********************");
print("调用");
--这样一个类就声明好了,下面我们来调用类里面的成员。
print("年龄是" .. tostring(Student.age));
--lua中类本质是一个table,所以可以使用索引来调用成员。
print("年龄是" .. tostring(Student["age"]));
--使用点来调用函数。
Student.Learn();
--使用索引调用函数。
Student["Learn"]();
--lua中如果一个类想要调用自身的一些属性,需要在方法调用的使用将自身作为参数传入。
--如果在类表的函数中直接调用相同名字的属性,这样相当于声明了一个全局变量,而这个变量和类表中的成员一点关系都没有。
Student.MyInfo(Student);

print("*********************");
print("点和冒号");
--上面我们知道了,如果一个类表中的函数想要使用本表的一些成员属性,就需要在调用时将表自身作为参数传进去,或者使用表名.成员的形式传入需要使用到额参数。
--但是lua为我们提供了一个语法糖,如下对比两者的结果相同。
Student.MyInfo(Student);
--冒号调用方法会默认把调用者作为第一个参数传入方法中。
Student:MyInfo();

print("*********************");
print("self关键字的使用");
--首先我们需要补充一个知识点,就是使用冒号声明函数
--只有使用冒号声明的函数才可以使用self关键字
--self关键字代表传入的第一个参数,可以说和冒号是天配。
--但需要注意self和C#的this不一样,因为lua是没有面向对象的概念的,所以作为系统的预留关键字也不会是面向对象的。
function Student:MyAge()
	print(self.age);
end

Student:MyAge();

Lua中table常用操作

print("*********************");
print("lua中table类型常用的一些函数");
print("插入操作");
--插入操作
--插入函数的前后参数分别为,被插入的表,要插入的表
--其中被插入的表需要是表中表的形式。
t1 = {{age = 1, name = "123"},{name = "yyy"}};
t2 = {name = "tian",sex = true};
table.insert(t1,t2);
for i=1,#t1 do
	print(t1[i].name);
end
print("*********************");
print("删除操作1");
--删除操作
--第一种移除方式
--参数只需要传入一个表,这种方式会移除表中的最后一个元素。
table.remove(t1);
for _,v in pairs(t1) do
	print(v.name)
end
print("*********************");
print("删除操作2");
--第二种移除方式
--传入两个参数,其中第一参数为要移除内容的表,第二个参数是要移除内容的索引。
table.remove(t1,1);
for _,v in pairs(t1) do
	print(v.name)
end
print("*********************");
print("排序,升序");
--在默认情况下只对number类型可以进行排序,且为升序排列
t2 = {6,5,4,3,3,2};
table.sort(t2);
for _,v in pairs(t2) do
	print(v)
end
--如果想要降序排列的效果或者其他特定的排序效果我们需要像C#那样传入一个函数,函数里面写一个判断条件
print("排序,降序");
table.sort(t2,function(a,b)
	if a > b then
		return true;
	end
end);
for _,v in pairs(t2) do
	print(v)
end
print("*********************");
print("拼接");
--拼接只用来拼接number类型和string类型
--参数分别为要拼接的表,拼接用的连接符,开始索引,结束索引
tb = {"aaa","bbb","ccc","ddd"};
str = table.concat( tb, "***");
print(str);

Lua多脚本执行

print("*********************");
print("全局变量和本地变量");
--全局变量,我们之前所写的所有变量都是全局的
ParamA = 1;
function func()
	ParamB = 2;
end
func();
print("这里是全局变量ParamA" .. ParamA);
print("这里是全局变量ParamB" .. ParamB);
--这里的ParamB也是可以在函数生命周期之外调用的,是全局变量。
--想要使用局部变量(本地变量),我们只需要加一个关键字local
function func2()
	local ParamC = 1;
end
func2();
print("由于局部变量ParamC没有被接收,这里lua会认为你要新建一个变量并赋值为nil");
print(ParamC);
--局部变量可以声明在函数之外,脚本之中,这样的局部变量在一个脚本中和全局变量没有什么区别
--但在多脚本执行中你就会知道这样写的作用是什么了。

print("*********************");
print("多脚本执行");
--关键字require("脚本名")
--我们创建一个脚本Test
--这里执行了lua_test脚本
require("lua_test");
--我们可以直接使用执行脚本的全局变量,但不能使用其局部变量。
--如果我们要使用其局部变量就需要使用return返回,并在调用脚本中接受返回值
print(requireParamA);

print("*********************");
print("脚本卸载");
--lua中一个特性,就是已经加载过一次的脚本不会加载第二次。
--这时如果我们有需要重新加载一次脚本,那么我们就需要将第一次加载的脚本卸载。
--我们可以通过下面这种方法来判断一个脚本是否被加载了。
--注意如果脚本有返回值,此方法会接受返回值。
print(package.loaded["lua_test"]);
--脚本卸载
package.loaded["lua_test"] = nil;
--这样我们就可以重新加载了。这里我们同时接收脚本的返回值并输出。
print(require("lua_test"));

print("*********************");
print("大G表");
--G表是一个总表(table),他将我们声明的所有全局变量都存储在其中。
--局部变量不会存储在_G表中。
--正是由于_G表的存在,我们才可以在一个脚本中随时随地的调用全局变量
for k,v in pairs(_G) do
	print(k,v)
end
--遍历中我们可以找到我们自己声明的全局变量

Lua特殊用法

print("*********************");
print("lua的一些特殊用法");
print("多变量赋值");
--传统赋值方式:
a = 1;
b = 2;
c = 3;
--多变量赋值:
a,b,c = 4,5,6;
print("三个变量的值分别为:" .. a .. b .. c);
--在lua中多变量赋值和多返回值都遵循自动补空和自动省略的处理策略。
--自动补空
a,b,c = 1,2;
print(a);
print(b);
print(c);
--自动省略
a,b,c = 1,2,3,4,5;
print(a);
print(b);
print(c);

print("*********************");
print("and和or的特殊用法");
--在lua中数值同样具有布尔意义。
--lua中只有nil和false为假,其他情况都为真。
--lua同样有短路逻辑。
--借助这些特性,我们就可以通过and和or来实现lua的三目运算符。
--先来看结果演示:
x = 1;
y = 2;
local result = (x > y) and x or y
print(result);
--这个结果和C#中的三目运算符的结果是一样的,?:,条件为真返回x,条件为假返回y。
--[[
下面我们来说一下原理:
根据短路逻辑
(x > y) --false
所以and式返回一个(x > y),也就是false
false继续和y做or运算
根据短路逻辑返回y

如果是(x > y) --true
根据短路逻辑返回一个x
x继续和y做or运算
根据短路逻辑返回x
]]

Lua协程

print("*********************");
print("lua协程");
print("协程的创建");
--方法一创建协程:coroutine.create();
function func()
	print("方式一创建协程");
end
function func1()
	print("方式二创建协程");
end
coroutine1 = coroutine.create(func);
--协程的本质是一个thread类型的对象,方式一创建的协程也是一个thread类型的。
--使用时需要使用特定API来使用。
print(type(coroutine1));
--方式二创建协程:coroutine.wrap();
coroutine2 = coroutine.wrap(func1);
--方式二创建的协程是一个function类型,使用的时候也和函数的使用过程一样。
print(type(coroutine2));

print("*********************");
print("lua协程的运行");
--第一种方式运行协程:
coroutine.resume(coroutine1);
--第二种方式:
coroutine2();

print("*********************");
print("lua协程的挂起");
func2 = function()
	local i = 1
	while true do
		print(i);
		i = i + 1;
		print(coroutine.running());
		--当coroutine3运行时显示running,当其他协程运行此函数显示suspended
		print(coroutine.status(coroutine3));
		--协程的挂起函数,可以返回返回值
		coroutine.yield(i);
	end
end

coroutine3 = coroutine.create(func2);
--每调用一次相当于C#的迭代器调用一次movenext方法,协程就会运行一次。
--由于lua是从上到下一次运行的,所以只用重启一次协程才可以运行一次。
--如果是使用resume创建的协程yield会返回两个返回值,第一个显示是否重启成功,第二个显示返回值。
isOk, tempI = coroutine.resume(coroutine3);
print(isOk,tempI);
coroutine.resume(coroutine3);
print(isOk,tempI);
coroutine.resume(coroutine3);
print(isOk,tempI);

--如果是使用wrap创建协程函数,yield只会返回一个返回值。
coroutine4 = coroutine.wrap(func2);
print("返回值为:" .. coroutine4());
print("返回值为:" .. coroutine4());
print("返回值为:" .. coroutine4());

print("*********************");
print("lua协程的状态");
--通过APIcoroutine.status()查询协程当前的状态。
--dead 协程结束
--suspended 暂停
--running 进行中
--其中运行中的协程才可以检测到running状态。
--coroutine.running()返回正在运行的线程编号,需要在协程内使用

Lua元表

print("*********************");
print("lua元表");
print("元表的概念");
--任何表都可以是另一个表的元表。
--任何表都可以有自己的元表。
--当我们在子表中进行一些特定操作时,会执行元表中的内容。
print("*********************");
print("设置元表");
meta = {};
myTable = {};
--为两个表变量设置元表关系,这里我们将被设置元表的一方称为子表。
--第一个参数:子表
--第二个参数:元表
setmetatable(myTable, meta);
print("*********************");
print("特定操作-__tostring");
--这里我们使用之前声明的元表关系
meta.__tostring = function(me)
	return me.name
end
myTable.name = "runto";
--注意,__tostring属于特殊操作,子表被当作字符串使用时,会调用元表中的__tostring方法。
--注意,子表中写这个方法是不会被调用的,除非该表也是某个表的元表。
myTable.__tostring = function(me)
	return 5;
end
print(myTable);
print("*********************");
print("特定操作-__call");
--这里我们继续使用meta和他的子表myTable。
--注意,__call属于特殊操作,当子表被当作字符串使用时,会调用元表中的__call方法。
--和__tostring一样,子表中写这个方法是不会被调用的,除非该表也是某个表的元表。
--其中第一个参数是调用者自身,第二参数之后为传入的参数。
--[[你可能已经注意到打印param1的结果是__tostring的结果,这很好解释:
我们已经知道__call的第一个参数是调用者自身,这里打印调用者lua会认为子表被当作字符串使用了,所以调用了元表中的__tostring方法。
]]
meta.__call = function(param1,param2)
	print(param1);
	print(param2);
	print("runto");
end
myTable(1);
print("*********************");
print("特定操作-运算符重载");
meta.__add = function(table1,table2)
	return 2;
end
meta.__concat = function(table1,table2)
	print("拼接");
end
--算术运算符重载不要求相加的两个元素必须都是表,不要求有相同的元表。
--[[
其他算数运算符重载需要写的变量名:
加法:__add
减法:__sub
乘法:__mul
除法:__div
取余:__mod
指数:__pow

--拼接也不受元素元表的影响,就先写在这里了
拼接:__concat
]]
myTable2 = {};
print(myTable2 .. myTable);
--条件运算符重载,要求两个元素有相同的元表才可以比较。
--[[
判等于:__eq
判大于:__lt
判大于等于:__le
相反操作取反即可
]]

print("*********************");
print("特定操作-__index和__newIndex");
print("__index");

--这里我们继续使用meta和他的子表myTable。
--首先我们给元表meta添加一个新的字段age
meta.age = 15;
function meta:GetAge()
	print(self.age);
end
--接下来如果我们调用子表myTable中的age会打印nil,毕竟我们并没有在子表中声明一个age的字段。
--但如果我为meta增添一个__index,并将meta赋值给__index
meta.__index = meta;
--结果打印为15
print(myTable:GetAge());
--这里我们来说一下__index的作用:当子表中找不到某一个属性或者方法时,
--如果元表写了__index,则子表接下来会去__index所指的表中查找。
print("__newIndex");
--__index主要针对于想要得到一个值,但在子表中没有的情况。
--__newIndex主要针对的是想要修改一个值,但子表中没有的情况,
--这时lua会将这个值赋值给__newIndex所指的表中,而不会修改自己的表。
--这里我们还是选择改变meta和myTable。
meta.__newindex = {};
myTable.level = 15;
--这里打印不出level信息
print(myTable.level);
--这里打印出了levle信息
print(meta.__newindex.level);

print("*********************");
print("获得一个表的元表,有设置就有获得");
print(getmetatable(myTable));

print("如果我们不想找元表,只想找自己中的元素,或者在自己中设置元素");
--使用rawget和rawset
rawset(myTable,"age",14);
print(rawget(myTable, "age"));

Lua面向对象

print("*********************");
print("利用lua实现封装");
--首先我们声明一个万物之父Object表
Object = {};
function Object:new()
	--self代表我们默认传入的第一个参数
	local obj = {};
	--这里使用元表的知识,当在本表中找不到一个元素时,就需要去其元表中去查找
	self.__index = self;
	--设定元表关系
	setmetatable(obj,self);
	return obj;
end
--继承
function Object:subClass(className)
	_G[className] = {};
	local obj = _G[className];
	--这里的base模拟的时C#中的base指向父类,通过base使用方法时不要使用:,因为使用:将调用父类的方法,
	--这里和C#不一样,因为在lua中没有类的概念,都是表,表可以理解为C#中的静态类,所以如果都调用父类的方法改变的将都是父类的成员。
	obj.base = self;
	--如果子类中没有就要去父类中查找,所以要设定__index
	self.__index = self;
	--设定元表关系
	setmetatable(obj,self);
end
--虽然new和subclass都是声明在Object中的方法,但是可以通过__index回溯到Object中调用。
--补充一下,:声明方法会将调用者作为第一个参数传入,所以当我们使用一个新类继承Object时,self传入的是新类。

Lua常用的一些自带库

print("*********************");
print("lua自带库");
print("常用时间获得");
--得到系统时间
print(os.time());
--自己输入参数,得到时间
print(os.time({year = 2014,month = 8,day = 14}));
--得到当前的年月日表
newTime = os.date("*t");
--遍历此表
for k,v in pairs(newTime) do
	print(k,v)
end
print("*********************");
print("常用数学运算");
--绝对值
print(math.abs(-11));
--弧度转角度
print(math.deg(math.pi));
--三角函数
print(math.cos(math.pi));
--向下取整
print(math.floor(2.6));
--向上取整
print(math.ceil(2.6));
--取最大值
print(math.max(1,2));
--取最小值
print(math.min(1,2));
--整数小数分离
print(math.modf(1.2));
--幂运算
print(math.pow(2,5));
--100以内的随机数,是伪随机数,需要设置随机数种子
math.randomseed(os.time());
print(math.random(100));
print(math.random(100));
--开方运算
print(math.sqrt(4));
print("*********************");
print("路径");
--查看lua的脚本加载路径
print(package.path);
--添加新的路径
package.path = package.path .. ";C:\\";
print(package.path);
print("*********************");
print("垃圾回收");
--垃圾回收关键字:collectgarbage
--获得当前lua占用的字节数,KB为单位,想要获得字节数需要使用返回值*1024
print(collectgarbage("count"));
--垃圾回收
test = {id = 1,name = "321321"};
print(collectgarbage("count"));
collectgarbage("collect");
--这里和C#的回收原理很像,接触羁绊就会变成垃圾
test = nil;
print(collectgarbage("count"));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值